From b78b8f64a69481e59e957ebe09315fc5b8b60c17 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Wed, 5 Oct 2011 03:36:48 -0400 Subject: [PATCH] Windows: Enforce Share Access 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 FIXES 130239 Change-Id: If9b4beb74586296d4feae52dd06c03f0b8b595cd Reviewed-on: http://gerrit.openafs.org/5823 Tested-by: BuildBot Reviewed-by: Jeffrey Altman Tested-by: Jeffrey Altman --- src/WINNT/afsd/cm_scache.h | 2 +- src/WINNT/afsd/cm_vnodeops.c | 81 ++++++---- src/WINNT/afsd/cm_vnodeops.h | 13 +- src/WINNT/afsd/smb3.c | 8 +- src/WINNT/afsrdr/common/AFSUserDefines.h | 8 + src/WINNT/afsrdr/common/AFSUserStructs.h | 21 +++ src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp | 38 +++++ src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp | 34 +++++ src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h | 6 + src/WINNT/afsrdr/user/RDRFunction.c | 187 ++++++++++++++++++++++- src/WINNT/afsrdr/user/RDRInit.cpp | 23 +++ src/WINNT/afsrdr/user/RDRPrototypes.h | 8 + 12 files changed, 386 insertions(+), 43 deletions(-) diff --git a/src/WINNT/afsd/cm_scache.h b/src/WINNT/afsd/cm_scache.h index f0ab19a..3829d6e 100644 --- a/src/WINNT/afsd/cm_scache.h +++ b/src/WINNT/afsd/cm_scache.h @@ -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 { diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index 0545350..365720e 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -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; diff --git a/src/WINNT/afsd/cm_vnodeops.h b/src/WINNT/afsd/cm_vnodeops.h index b251f4a..fd2275a 100644 --- a/src/WINNT/afsd/cm_vnodeops.h +++ b/src/WINNT/afsd/cm_vnodeops.h @@ -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); diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 7c453f3..1dec90a 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -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); diff --git a/src/WINNT/afsrdr/common/AFSUserDefines.h b/src/WINNT/afsrdr/common/AFSUserDefines.h index a39a24c..2edd288 100644 --- a/src/WINNT/afsrdr/common/AFSUserDefines.h +++ b/src/WINNT/afsrdr/common/AFSUserDefines.h @@ -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 @@ -300,5 +301,12 @@ #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 */ diff --git a/src/WINNT/afsrdr/common/AFSUserStructs.h b/src/WINNT/afsrdr/common/AFSUserStructs.h index 4c1cd87..34496fd 100644 --- a/src/WINNT/afsrdr/common/AFSUserStructs.h +++ b/src/WINNT/afsrdr/common/AFSUserStructs.h @@ -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; // diff --git a/src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp b/src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp index c56faf4..527c675 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp @@ -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, diff --git a/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp b/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp index 46dbc45..c534890 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp @@ -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) { diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h index ab05462..37b9c70 100644 --- a/src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h @@ -140,6 +140,12 @@ typedef struct _AFS_CCB } FileUnwindInfo; + // + // Granted File Access + // + + ULONG FileAccess; + } AFSCcb; // diff --git a/src/WINNT/afsrdr/user/RDRFunction.c b/src/WINNT/afsrdr/user/RDRFunction.c index cf6fcad..d618489 100644 --- a/src/WINNT/afsrdr/user/RDRFunction.c +++ b/src/WINNT/afsrdr/user/RDRFunction.c @@ -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) { diff --git a/src/WINNT/afsrdr/user/RDRInit.cpp b/src/WINNT/afsrdr/user/RDRInit.cpp index 7d123e2..91e178e 100644 --- a/src/WINNT/afsrdr/user/RDRInit.cpp +++ b/src/WINNT/afsrdr/user/RDRInit.cpp @@ -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); diff --git a/src/WINNT/afsrdr/user/RDRPrototypes.h b/src/WINNT/afsrdr/user/RDRPrototypes.h index a323689..2130fe0 100644 --- a/src/WINNT/afsrdr/user/RDRPrototypes.h +++ b/src/WINNT/afsrdr/user/RDRPrototypes.h @@ -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, -- 1.9.4