Windows: Enforce Share Access
authorJeffrey Altman <jaltman@your-file-system.com>
Wed, 5 Oct 2011 07:36:48 +0000 (03:36 -0400)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Fri, 11 Nov 2011 18:00:41 +0000 (10:00 -0800)
Use file server locks to enforce file share access modes
via the afs redirector interface.  The approach taken
integrates share mode enforcement with the file server
lock tracking code in the service.  The share mode
enforcement mimics that of the SMB Server interface.

This patchset includes two functional changes to
the previous locking and share mode processing:

 1. The cm_scache_t fsLockCount field is used to
    determine if the desired lock can be granted
    by the file server.  If not, the RXAFS_SetLock()
    request is skipped and the request is failed
    locally.

 2. cm_CheckNTOpen() now accepts the desired and
    and share access modes.  The share access mode
    is used to determine if a test lock should be
    obtained at all.  If the share mode is FILE_SHARE_WRITE
    then no lock is requested.  This change permits
    Microsoft Office applications to offer the user
    the ability to open the file in read-only mode
    and notify the user when the document can be
    opened in read-write mode.

Developed with Peter Scott <pscott@kerneldrivers.com>

FIXES 130239

Change-Id: If9b4beb74586296d4feae52dd06c03f0b8b595cd
Reviewed-on: http://gerrit.openafs.org/5823
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Jeffrey Altman <jaltman@secure-endpoints.com>
Tested-by: Jeffrey Altman <jaltman@secure-endpoints.com>

12 files changed:
src/WINNT/afsd/cm_scache.h
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/cm_vnodeops.h
src/WINNT/afsd/smb3.c
src/WINNT/afsrdr/common/AFSUserDefines.h
src/WINNT/afsrdr/common/AFSUserStructs.h
src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp
src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp
src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h
src/WINNT/afsrdr/user/RDRFunction.c
src/WINNT/afsrdr/user/RDRInit.cpp
src/WINNT/afsrdr/user/RDRPrototypes.h

index f0ab19a..3829d6e 100644 (file)
@@ -26,7 +26,7 @@ typedef struct cm_fid {
 typedef struct cm_key {
     afs_offs_t process_id;      /* process IDs can be 64bit on 64bit environments */
     afs_uint16 session_id;
-    afs_uint16 file_id;
+    afs_uint64 file_id;         /* afs redir uses File Object pointers as file id */
 } cm_key_t;
 
 typedef struct cm_range {
index 0545350..365720e 100644 (file)
@@ -178,16 +178,30 @@ long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
 }
 
 /* return success if we can open this file in this mode */
-long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
-                    unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp,
+long cm_CheckNTOpen(cm_scache_t *scp,
+                    unsigned int desiredAccess,
+                    unsigned int shareAccess,
+                    unsigned int createDisp,
+                    afs_offs_t process_id,
+                    afs_offs_t handle_id,
+                    cm_user_t *userp, cm_req_t *reqp,
                    cm_lock_data_t **ldpp)
 {
     long rights;
     long code = 0;
+    afs_uint16 session_id;
 
     osi_assertx(ldpp != NULL, "null cm_lock_data_t");
     *ldpp = NULL;
 
+    /* compute the session id */
+    if (reqp->flags & CM_REQ_SOURCE_SMB)
+        session_id = CM_SESSION_SMB;
+    else if (reqp->flags & CM_REQ_SOURCE_REDIR)
+        session_id = CM_SESSION_IFS;
+    else
+        session_id = CM_SESSION_CMINT;
+
     /* Ignore the SYNCHRONIZE privilege */
     desiredAccess &= ~SYNCHRONIZE;
 
@@ -231,8 +245,9 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
         code = CM_ERROR_NOACCESS;
 
     if (code == 0 &&
-             ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
-             scp->fileType == CM_SCACHETYPE_FILE) {
+        !(shareAccess & FILE_SHARE_WRITE) &&
+        ((rights & PRSFS_WRITE) || (rights & PRSFS_READ)) &&
+        scp->fileType == CM_SCACHETYPE_FILE) {
         cm_key_t key;
         unsigned int sLockType;
         LARGE_INTEGER LOffset, LLength;
@@ -240,12 +255,13 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
         /* Check if there's some sort of lock on the file at the
            moment. */
 
-        key = cm_GenerateKey(CM_SESSION_CMINT,0,0);
         if (rights & PRSFS_WRITE)
             sLockType = 0;
         else
             sLockType = LOCKING_ANDX_SHARED_LOCK;
 
+        key = cm_GenerateKey(session_id, process_id, 0);
+
         /* single byte lock at offset 0x0100 0000 0000 0000 */
         LOffset.HighPart = CM_FLSHARE_OFFSET_HIGH;
         LOffset.LowPart  = CM_FLSHARE_OFFSET_LOW;
@@ -255,29 +271,30 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
 
         if (code == 0) {
-           (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
-           if (!*ldpp) {
-               code = ENOMEM;
-               goto _done;
-           }
+            (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
+            if (!*ldpp) {
+                code = ENOMEM;
+                goto _done;
+            }
 
-           (*ldpp)->key = key;
-           (*ldpp)->sLockType = sLockType;
-           (*ldpp)->LOffset.HighPart = LOffset.HighPart;
-           (*ldpp)->LOffset.LowPart = LOffset.LowPart;
-           (*ldpp)->LLength.HighPart = LLength.HighPart;
-           (*ldpp)->LLength.LowPart = LLength.LowPart;
+            (*ldpp)->key = key;
+            (*ldpp)->sLockType = sLockType;
+            (*ldpp)->LOffset.HighPart = LOffset.HighPart;
+            (*ldpp)->LOffset.LowPart = LOffset.LowPart;
+            (*ldpp)->LLength.HighPart = LLength.HighPart;
+            (*ldpp)->LLength.LowPart = LLength.LowPart;
         } else {
-            /* In this case, we allow the file open to go through even
-               though we can't enforce mandatory locking on the
-               file. */
+            /*
+             * In this case, we allow the file open to go through even
+             * though we can't enforce mandatory locking on the
+             * file. */
             if (code == CM_ERROR_NOACCESS &&
-                !(rights & PRSFS_WRITE))
+                 !(rights & PRSFS_WRITE))
                 code = 0;
             else {
-               if (code == CM_ERROR_LOCK_NOT_GRANTED)
-                   code = CM_ERROR_SHARING_VIOLATION;
-           }
+                if (code == CM_ERROR_LOCK_NOT_GRANTED)
+                    code = CM_ERROR_SHARING_VIOLATION;
+            }
         }
     } else if (code != 0) {
         goto _done;
@@ -294,9 +311,9 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
 extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
                               cm_lock_data_t ** ldpp)
 {
-    osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, *ldpp);
+       osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, ldpp ? *ldpp : 0);
     lock_ObtainWrite(&scp->rw);
-    if (*ldpp) {
+    if (ldpp && *ldpp) {
        cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength,
                  (*ldpp)->key, 0, userp, reqp);
        free(*ldpp);
@@ -4417,6 +4434,16 @@ long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
     AFSVolSync volSync;
     afs_uint32 reqflags = reqp->flags;
 
+    osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
+
+       if ((lockType != LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount != 0) ||
+               (lockType == LOCKING_ANDX_SHARED_LOCK && scp->fsLockCount < 0))
+       {
+               code = CM_ERROR_LOCK_NOT_GRANTED;
+        osi_Log2(afsd_logp, "CALL SetLock FAILURE, fsLockCount %d code 0x%x", scp->fsLockCount, code);
+               return code;
+       }
+
     memset(&volSync, 0, sizeof(volSync));
 
     tfid.Volume = scp->fid.volume;
@@ -4424,8 +4451,6 @@ long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
     tfid.Unique = scp->fid.unique;
     cfid = scp->fid;
 
-    osi_Log2(afsd_logp, "CALL SetLock scp 0x%p for lock %d", scp, lockType);
-
     reqp->flags |= CM_REQ_NORETRY;
     lock_ReleaseWrite(&scp->rw);
 
@@ -5889,7 +5914,7 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
     return code;
 }
 
-cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16 file_id)
+cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint64 file_id)
 {
     cm_key_t key;
 
index b251f4a..fd2275a 100644 (file)
@@ -174,9 +174,14 @@ typedef struct cm_lock_data {
     LARGE_INTEGER LOffset, LLength;
 } cm_lock_data_t;
 
-extern long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
-                           unsigned int createDisp, cm_user_t *userp,
-                           cm_req_t *reqp, cm_lock_data_t ** ldpp);
+extern long cm_CheckNTOpen(cm_scache_t *scp,
+                           unsigned int desiredAccess,
+                           unsigned int shareAccess,
+                           unsigned int createDisp,
+                           afs_offs_t process_id,
+                           afs_offs_t handle_id,
+                           cm_user_t *userp, cm_req_t *reqp,
+                           cm_lock_data_t ** ldpp);
 
 extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
                               cm_lock_data_t ** ldpp);
@@ -233,7 +238,7 @@ extern long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead);
 #define CM_SESSION_CMINT    0xfffd
 #define CM_SESSION_RESERVED 0xfff0
 
-extern cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16 file_id);
+extern cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint64 file_id);
 
 extern int cm_KeyEquals(cm_key_t * k1, cm_key_t * k2, int flags);
 
index 7c453f3..1dec90a 100644 (file)
@@ -7827,7 +7827,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
      * scp is NULL.
      */
     if (code == 0 && !treeCreate) {
-        code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+        code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
         if (code) {
             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp)
@@ -7874,7 +7874,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                     cm_ReleaseSCache(scp);
                     scp = targetScp;
-                   code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+                   code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
                    if (code) {
                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                        if (dscp)
@@ -8621,7 +8621,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
      * scp is NULL.
      */
     if (code == 0) {
-        code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+        code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
         if (code) {
             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(dscp);
@@ -8663,7 +8663,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                     cm_ReleaseSCache(scp);
                     scp = targetScp;
-                   code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+                   code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
                    if (code) {
                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                         cm_ReleaseSCache(dscp);
index a39a24c..2edd288 100644 (file)
@@ -89,6 +89,7 @@
 #define AFS_REQUEST_TYPE_CREATE_LINK             0x0000001E
 #define AFS_REQUEST_TYPE_CREATE_MOUNTPOINT       0x0000001F
 #define AFS_REQUEST_TYPE_CREATE_SYMLINK          0x00000020
+#define AFS_REQUEST_TYPE_RELEASE_FILE_ACCESS     0x00000021
 
 //
 // Request Flags, these are passed up from the file system
 #define AFS_SYSNAME_ARCH_32BIT 0
 #define AFS_SYSNAME_ARCH_64BIT 1
 
+//
+// Server file access granted to callers on open
+//
+
+#define AFS_FILE_ACCESS_NOLOCK          0x00000000
+#define AFS_FILE_ACCESS_EXCLUSIVE       0x00000001
+#define AFS_FILE_ACCESS_SHARED          0x00000002
 
 #endif /* _AFS_USER_DEFINE_H */
index 4c1cd87..34496fd 100644 (file)
@@ -303,6 +303,10 @@ typedef struct _AFS_FILE_OPEN_CB
 
     ULONG           ShareAccess;
 
+    ULONGLONG       ProcessId;
+
+    ULONGLONG       Identifier;
+
 } AFSFileOpenCB;
 
 typedef struct _AFS_FILE_OPEN_RESULT_CB
@@ -310,8 +314,21 @@ typedef struct _AFS_FILE_OPEN_RESULT_CB
 
     ULONG           GrantedAccess;
 
+    ULONG           FileAccess;
+
 } AFSFileOpenResultCB;
 
+typedef struct _AFS_FILE_ACCESS_RELEASE_CB
+{
+
+    ULONG           FileAccess;
+
+    ULONGLONG       ProcessId;
+
+    ULONGLONG       Identifier;
+
+} AFSFileAccessReleaseCB;
+
 //
 // IO Interace control blocks for extent processing when performing
 // queries via the AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS or synchronous
@@ -956,6 +973,10 @@ typedef struct _AFS_FILE_CLEANUP_CB
 
     ULONGLONG       ProcessId;
 
+    ULONG           FileAccess;
+
+    ULONGLONG       Identifier;
+
 } AFSFileCleanupCB;
 
 //
index c56faf4..527c675 100644 (file)
@@ -108,6 +108,8 @@ AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
 
         stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
 
+        stFileCleanup.Identifier = (ULONGLONG)pFileObject;
+
         //
         // Perform the cleanup functionality depending on the type of node it is
         //
@@ -359,6 +361,12 @@ AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
 
                     //
+                    // Indicate the file access mode that is being released
+                    //
+
+                    stFileCleanup.FileAccess = pCcb->FileAccess;
+
+                    //
                     // Push the request to the service
                     //
 
@@ -521,6 +529,12 @@ AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
                     }
 
                     //
+                    // Indicate the file access mode that is being released
+                    //
+
+                    stFileCleanup.FileAccess = pCcb->FileAccess;
+
+                    //
                     // Push the request to the service
                     //
 
@@ -683,6 +697,12 @@ AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
 
                     //
+                    // Indicate the file access mode that is being released
+                    //
+
+                    stFileCleanup.FileAccess = pCcb->FileAccess;
+
+                    //
                     // Push the request to the service
                     //
 
@@ -785,6 +805,12 @@ AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
                         }
                     }
 
+                    //
+                    // Indicate the file access mode that is being released
+                    //
+
+                    stFileCleanup.FileAccess = pCcb->FileAccess;
+
                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
                                        &pFcb->AuthGroup,
@@ -936,6 +962,12 @@ AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
 
                     //
+                    // Indicate the file access mode that is being released
+                    //
+
+                    stFileCleanup.FileAccess = pCcb->FileAccess;
+
+                    //
                     // Push the request to the service
                     //
 
@@ -1038,6 +1070,12 @@ AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
                         }
                     }
 
+                    //
+                    // Indicate the file access mode that is being released
+                    //
+
+                    stFileCleanup.FileAccess = pCcb->FileAccess;
+
                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
                                        &pFcb->AuthGroup,
index 46dbc45..c534890 100644 (file)
@@ -2416,6 +2416,8 @@ AFSProcessOpen( IN PIRP Irp,
     ULONG       ulResultLen = 0;
     AFSObjectInfoCB *pParentObjectInfo = NULL;
     AFSObjectInfoCB *pObjectInfo = NULL;
+    ULONG       ulFileAccess = 0;
+    AFSFileAccessReleaseCB stReleaseFileAccess;
 
     __Enter
     {
@@ -2666,6 +2668,10 @@ AFSProcessOpen( IN PIRP Irp,
 
         stOpenCB.ShareAccess = usShareAccess;
 
+        stOpenCB.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
+
+        stOpenCB.Identifier = (ULONGLONG)pFileObject;
+
         stOpenResultCB.GrantedAccess = 0;
 
         ulResultLen = sizeof( AFSFileOpenResultCB);
@@ -2694,6 +2700,12 @@ AFSProcessOpen( IN PIRP Irp,
         }
 
         //
+        // Save the granted access in case we need to release it below
+        //
+
+        ulFileAccess = stOpenResultCB.FileAccess;
+
+        //
         // Check if there is a conflict
         //
 
@@ -2739,6 +2751,8 @@ AFSProcessOpen( IN PIRP Irp,
 
         (*Ccb)->DirectoryCB = DirectoryCB;
 
+        (*Ccb)->FileAccess = ulFileAccess;
+
         //
         // Perform the access check on the target if this is a mount point or symlink
         //
@@ -2856,6 +2870,26 @@ try_exit:
         if( !NT_SUCCESS( ntStatus))
         {
 
+            if ( ulFileAccess > 0)
+            {
+
+                stReleaseFileAccess.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
+
+                stReleaseFileAccess.FileAccess = ulFileAccess;
+
+                stReleaseFileAccess.Identifier = (ULONGLONG)pFileObject;
+
+                AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_ACCESS,
+                                   AFS_REQUEST_FLAG_SYNCHRONOUS,
+                                   AuthGroup,
+                                   &DirectoryCB->NameInformation.FileName,
+                                   &pObjectInfo->FileId,
+                                   (void *)&stReleaseFileAccess,
+                                   sizeof( AFSFileAccessReleaseCB),
+                                   NULL,
+                                   NULL);
+            }
+
             if( bAllocatedCcb)
             {
 
index ab05462..37b9c70 100644 (file)
@@ -140,6 +140,12 @@ typedef struct _AFS_CCB
 
     } FileUnwindInfo;
 
+    //
+    // Granted File Access
+    //
+
+    ULONG               FileAccess;
+
 } AFSCcb;
 
 //
index cf6fcad..d618489 100644 (file)
@@ -1645,6 +1645,7 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     BOOL                bScpLocked = FALSE;
     BOOL                bDscpLocked = FALSE;
     BOOL                bFlushFile = FALSE;
+    cm_key_t            key;
 
     RDR_InitReq(&req);
     if ( bWow64 )
@@ -1806,8 +1807,6 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     }
 
     if (bUnlockFile || bDeleteFile) {
-        cm_key_t    key;
-
         if (!bScpLocked) {
             lock_ObtainWrite(&scp->rw);
             bScpLocked = TRUE;
@@ -1820,9 +1819,9 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
             goto on_error;
         }
 
-        /* the scp is now locked and current */
         key = cm_GenerateKey(CM_SESSION_IFS, CleanupCB->ProcessId, 0);
 
+        /* the scp is now locked and current */
         code = cm_UnlockByKey(scp, key,
                               bDeleteFile ? CM_UNLOCK_FLAG_BY_FID : 0,
                               userp, &req);
@@ -1888,6 +1887,44 @@ RDR_CleanupFileEntry( IN cm_user_t *userp,
     } else
         code = 0;
 
+    /* Now drop the lock enforcing the share access */
+    if ( CleanupCB->FileAccess != AFS_FILE_ACCESS_NOLOCK) {
+        unsigned int sLockType;
+        LARGE_INTEGER LOffset, LLength;
+
+        if (CleanupCB->FileAccess == AFS_FILE_ACCESS_SHARED)
+            sLockType = LOCKING_ANDX_SHARED_LOCK;
+        else
+            sLockType = 0;
+
+        key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, CleanupCB->Identifier);
+
+        LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+        LOffset.LowPart = SMB_FID_QLOCK_LOW;
+        LLength.HighPart = 0;
+        LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+        if (!bScpLocked) {
+            lock_ObtainWrite(&scp->rw);
+            bScpLocked = TRUE;
+        }
+
+        code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
+        if (code == 0)
+        {
+            code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
+
+            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
+            if (code == CM_ERROR_RANGE_NOT_LOCKED)
+            {
+                osi_Log3(afsd_logp, "RDR_CleanupFileEntry Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
+                         CleanupCB->FileAccess, CleanupCB->ProcessId, CleanupCB->Identifier);
+
+            }
+        }
+    }
+
   on_error:
     if (bDscpLocked)
         lock_ReleaseWrite(&dscp->rw);
@@ -2600,9 +2637,13 @@ RDR_OpenFileEntry( IN cm_user_t *userp,
         osi_Log1(afsd_logp, "RDR_OpenFileEntry LOCAL_SYSTEM access check skipped scp=0x%p",
                  scp);
         pResultCB->GrantedAccess = OpenCB->DesiredAccess;
+        pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
         code = 0;
-    } else {
+    }
+    else
+    {
         int count = 0;
+
         do {
             if (count++ > 0) {
                 Sleep(350);
@@ -2610,15 +2651,64 @@ RDR_OpenFileEntry( IN cm_user_t *userp,
                          "RDR_OpenFileEntry repeating open check scp=0x%p userp=0x%p code=0x%x",
                          scp, userp, code);
             }
-            code = cm_CheckNTOpen(scp, OpenCB->DesiredAccess, OPEN_ALWAYS, userp, &req, &ldp);
+            code = cm_CheckNTOpen(scp, OpenCB->DesiredAccess, OpenCB->ShareAccess,
+                                  OPEN_ALWAYS,
+                                  OpenCB->ProcessId, OpenCB->Identifier,
+                                  userp, &req, &ldp);
             if (code == 0)
                 code = RDR_CheckAccess(scp, userp, &req, OpenCB->DesiredAccess, &pResultCB->GrantedAccess);
             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         } while (count < 100 && (code == CM_ERROR_RETRY || code == CM_ERROR_WOULDBLOCK));
     }
 
+    /*
+     * If we are restricting sharing, we should do so with a suitable
+     * share lock.
+     */
+    if (code == 0 && scp->fileType == CM_SCACHETYPE_FILE && !(OpenCB->ShareAccess & FILE_SHARE_WRITE)) {
+        cm_key_t key;
+        LARGE_INTEGER LOffset, LLength;
+        int sLockType;
+
+        LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+        LOffset.LowPart = SMB_FID_QLOCK_LOW;
+        LLength.HighPart = 0;
+        LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+        /*
+         * If we are not opening the file for writing, then we don't
+         * try to get an exclusive lock.  No one else should be able to
+         * get an exclusive lock on the file anyway, although someone
+         * else can get a shared lock.
+         */
+        if ((OpenCB->ShareAccess & FILE_SHARE_READ) || !(OpenCB->DesiredAccess & AFS_ACCESS_WRITE))
+        {
+            sLockType = LOCKING_ANDX_SHARED_LOCK;
+        } else {
+            sLockType = 0;
+        }
+
+        key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, OpenCB->Identifier);
+
+        lock_ObtainWrite(&scp->rw);
+        code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
+        lock_ReleaseWrite(&scp->rw);
+
+        if (code) {
+            code = CM_ERROR_SHARING_VIOLATION;
+            pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
+        } else {
+            if (sLockType == LOCKING_ANDX_SHARED_LOCK)
+                pResultCB->FileAccess = AFS_FILE_ACCESS_SHARED;
+            else
+                pResultCB->FileAccess = AFS_FILE_ACCESS_EXCLUSIVE;
+        }
+    } else {
+        pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
+    }
+
     cm_ReleaseUser(sysUserp);
-    if (bHoldFid)
+    if (code == 0 && bHoldFid)
         RDR_FlagScpInUse( scp, FALSE );
     cm_ReleaseSCache(scp);
 
@@ -2635,6 +2725,91 @@ RDR_OpenFileEntry( IN cm_user_t *userp,
     return;
 }
 
+void
+RDR_ReleaseFileAccess( IN cm_user_t *userp,
+                       IN AFSFileID FileId,
+                       IN AFSFileAccessReleaseCB *ReleaseFileCB,
+                       IN BOOL bWow64,
+                       IN DWORD ResultBufferLength,
+                       IN OUT AFSCommResult **ResultCB)
+{
+    cm_key_t key;
+    unsigned int sLockType;
+    LARGE_INTEGER LOffset, LLength;
+    cm_scache_t *scp = NULL;
+    cm_fid_t    Fid;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_ReleaseFileAccess File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+              FileId.Cell, FileId.Volume,
+              FileId.Vnode, FileId.Unique);
+
+    *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
+    if (!(*ResultCB)) {
+        osi_Log0(afsd_logp, "RDR_ReleaseFileAccess out of memory");
+       return;
+    }
+
+    memset( *ResultCB, '\0', sizeof( AFSCommResult));
+
+    if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_NOLOCK)
+        return;
+
+    /* Process the release */
+    Fid.cell = FileId.Cell;
+    Fid.volume = FileId.Volume;
+    Fid.vnode = FileId.Vnode;
+    Fid.unique = FileId.Unique;
+    Fid.hash = FileId.Hash;
+
+    code = cm_GetSCache(&Fid, &scp, userp, &req);
+    if (code) {
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        osi_Log2(afsd_logp, "RDR_ReleaseFileAccess cm_GetSCache FID failure code=0x%x status=0x%x",
+                  code, status);
+        return;
+    }
+
+    if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_SHARED)
+        sLockType = LOCKING_ANDX_SHARED_LOCK;
+    else
+        sLockType = 0;
+
+    key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, ReleaseFileCB->Identifier);
+
+    LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+    LOffset.LowPart = SMB_FID_QLOCK_LOW;
+    LLength.HighPart = 0;
+    LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+    lock_ObtainWrite(&scp->rw);
+
+    code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
+    if (code == 0)
+    {
+        code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
+
+        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
+        if (code == CM_ERROR_RANGE_NOT_LOCKED)
+        {
+            osi_Log3(afsd_logp, "RDR_ReleaseFileAccess Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
+                     ReleaseFileCB->FileAccess, ReleaseFileCB->ProcessId, ReleaseFileCB->Identifier);
+        }
+    }
+
+    lock_ReleaseWrite(&scp->rw);
+
+    osi_Log0(afsd_logp, "RDR_ReleaseFileAccessEntry SUCCESS");
+}
+
 static const char *
 HexCheckSum(unsigned char * buf, int buflen, unsigned char * md5cksum)
 {
index 7d123e2..91e178e 100644 (file)
@@ -800,6 +800,29 @@ RDR_ProcessRequest( AFSCommRequest *RequestBuffer)
             break;
         }
 
+        case AFS_REQUEST_TYPE_RELEASE_FILE_ACCESS:
+        {
+            AFSFileAccessReleaseCB *pFileAccessReleaseCB = (AFSFileAccessReleaseCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
+
+            if (afsd_logp->enabled) {
+                swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_RELEASE_FILE_ACCESS Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                          RequestBuffer->RequestIndex,
+                          RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                          RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+            }
+
+            RDR_ReleaseFileAccess( userp,
+                                   RequestBuffer->FileId,
+                                   pFileAccessReleaseCB,
+                                   bWow64,
+                                   RequestBuffer->ResultBufferLength,
+                                   &pResultCB);
+
+            break;
+        }
+
         case AFS_REQUEST_TYPE_PIOCTL_OPEN:
         {
             AFSPIOCtlOpenCloseRequestCB *pPioctlCB = (AFSPIOCtlOpenCloseRequestCB *)((char *)RequestBuffer->Name + RequestBuffer->DataOffset);
index a323689..2130fe0 100644 (file)
@@ -149,6 +149,14 @@ RDR_OpenFileEntry( IN cm_user_t *userp,
                    IN OUT AFSCommResult **ResultCB);
 
 void
+RDR_ReleaseFileAccess( IN cm_user_t *userp,
+                       IN AFSFileID FileId,
+                       IN AFSFileAccessReleaseCB *ReleaseFileCB,
+                       IN BOOL bWow64,
+                       IN DWORD ResultBufferLength,
+                       IN OUT AFSCommResult **ResultCB);
+
+void
 RDR_CleanupFileEntry( IN cm_user_t *userp,
                       IN AFSFileID FileId,
                       IN WCHAR *FileName,