From 561b9ce80938d316223f2b313f8224fe06af9d5a Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Tue, 3 Jul 2012 15:38:33 -0400 Subject: [PATCH] Windows: RDR RXAFS_GetVolumeStatus vs 1.1 'l' only The Windows redirector relies upon the ability to obtain volume status information to decide whether a file system volume object can be created and whether or not an extending write can be permitted. As of this writing, the file server always performs a PRFS_READ access check on the volume's root directory (1.1) vnode as a condition for releasing the volume state information which includes: Message of the day (if any) Offline message (if any) Online flag InService flag Blessed flag NeedsSalvage flag Type MinQuota MaxQuota BlocksInUse PartBlocksAvail PartMaxBlocks All of this information is publicly available to anonymous users via "vos examine" so it is odd that it is hidden from anonymous cache managers. When RXAFS_GetVolumeStatus fails, the AFS redirector was failing to create a file system object for the AFS volume. That in turn prevented the volume from being accessed even if the user had 'l' in the root directory and full access everywhere else. This patchset will make up fake data for the AFS volume if the RPC fails. However, doing so does have consequences. The client will be unable to make an accurate determination regarding free space on the file server. As a result, an extending write may be permitted which writes data into the system page cache which in turn cannot be written to the file server. Such data will be lost and unrecoverable. Change-Id: Ic818ce9d51893181941f41d6628394b5917dc811 Reviewed-on: http://gerrit.openafs.org/7704 Tested-by: BuildBot Reviewed-by: Jeffrey Altman Tested-by: Jeffrey Altman --- src/WINNT/afsrdr/user/RDRFunction.c | 152 ++++++++++++++++------------ 1 file changed, 86 insertions(+), 66 deletions(-) diff --git a/src/WINNT/afsrdr/user/RDRFunction.c b/src/WINNT/afsrdr/user/RDRFunction.c index 4eddf0115..a1174bab4 100644 --- a/src/WINNT/afsrdr/user/RDRFunction.c +++ b/src/WINNT/afsrdr/user/RDRFunction.c @@ -4956,7 +4956,6 @@ RDR_GetVolumeInfo( IN cm_user_t *userp, DWORD Length; cm_scache_t *scp = NULL; cm_volume_t *volp = NULL; - cm_vol_state_t *volstatep = NULL; afs_uint32 volType; cm_cell_t *cellp = NULL; cm_fid_t Fid; @@ -4974,6 +4973,8 @@ RDR_GetVolumeInfo( IN cm_user_t *userp, char *OfflineMsg; char *MOTD; struct rx_connection * rxconnp; + int sync_done = 0; + int scp_locked = 0; RDR_InitReq(&req); if ( bWow64 ) @@ -5017,18 +5018,7 @@ RDR_GetVolumeInfo( IN cm_user_t *userp, return; } lock_ObtainWrite(&scp->rw); - - code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ, - CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); - if (code) { - lock_ReleaseWrite(&scp->rw); - smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE); - (*ResultCB)->ResultStatus = status; - (*ResultCB)->ResultBufferLength = 0; - osi_Log3(afsd_logp, "RDR_GetVolumeInfo cm_SyncOp failure scp=0x%p code=0x%x status=0x%x", - scp, code, status); - return; - } + scp_locked = 1; pResultCB->SectorsPerAllocationUnit = 1; pResultCB->BytesPerSector = 1024; @@ -5060,26 +5050,35 @@ RDR_GetVolumeInfo( IN cm_user_t *userp, code = CM_ERROR_NOSUCHVOLUME; goto _done; } - volstatep = cm_VolumeStateByID(volp, scp->fid.volume); volType = cm_VolumeType(volp, scp->fid.volume); pResultCB->Characteristics |= ((volType == ROVOL || volType == BACKVOL) ? FILE_READ_ONLY_DEVICE : 0); - Name = volName; - OfflineMsg = offLineMsg; - MOTD = motd; - lock_ReleaseWrite(&scp->rw); - do { - code = cm_ConnFromFID(&scp->fid, userp, &req, &connp); - if (code) continue; - - rxconnp = cm_GetRxConn(connp); - code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume, - &volStat, &Name, &OfflineMsg, &MOTD); - rx_PutConnection(rxconnp); - - } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, code)); - code = cm_MapRPCError(code, &req); + code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ, + CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + if (code == 0) + { + sync_done = 1; + + Name = volName; + OfflineMsg = offLineMsg; + MOTD = motd; + lock_ReleaseWrite(&scp->rw); + scp_locked = 0; + + do { + code = cm_ConnFromFID(&scp->fid, userp, &req, &connp); + if (code) continue; + + rxconnp = cm_GetRxConn(connp); + code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume, + &volStat, &Name, &OfflineMsg, &MOTD); + rx_PutConnection(rxconnp); + + } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, code)); + code = cm_MapRPCError(code, &req); + } + if (code == 0) { if (volStat.MaxQuota) { @@ -5105,8 +5104,13 @@ RDR_GetVolumeInfo( IN cm_user_t *userp, } } } else { + /* + * Lie about the available space. Out of quota errors will need + * detected when the file server rejects the store data. + */ pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF; pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000; + code = 0; } pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( volp->namep, -1, pResultCB->VolumeLabel, @@ -5114,14 +5118,19 @@ RDR_GetVolumeInfo( IN cm_user_t *userp, if ( pResultCB->VolumeLabelLength ) pResultCB->VolumeLabelLength--; - lock_ObtainWrite(&scp->rw); + if (sync_done) { + if (!scp_locked) { + lock_ObtainWrite(&scp->rw); + scp_locked = 1; + } + cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + } } pResultCB->VolumeLabelLength *= sizeof(WCHAR); /* convert to bytes from chars */ - cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); - _done: - lock_ReleaseWrite(&scp->rw); + if (scp_locked) + lock_ReleaseWrite(&scp->rw); if (volp) cm_PutVolume(volp); cm_ReleaseSCache(scp); @@ -5159,6 +5168,8 @@ RDR_GetVolumeSizeInfo( IN cm_user_t *userp, char *OfflineMsg; char *MOTD; struct rx_connection * rxconnp; + int sync_done = 0; + int scp_locked = 0; RDR_InitReq(&req); if ( bWow64 ) @@ -5202,24 +5213,13 @@ RDR_GetVolumeSizeInfo( IN cm_user_t *userp, return; } lock_ObtainWrite(&scp->rw); - - code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ, - CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); - if (code) { - lock_ReleaseWrite(&scp->rw); - smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE); - (*ResultCB)->ResultStatus = status; - (*ResultCB)->ResultBufferLength = 0; - osi_Log3(afsd_logp, "RDR_GetVolumeSizeInfo cm_SyncOp failure scp=0x%p code=0x%x status=0x%x", - scp, code, status); - return; - } + scp_locked = 1; pResultCB->SectorsPerAllocationUnit = 1; pResultCB->BytesPerSector = 1024; if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID && - scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) + scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) { pResultCB->TotalAllocationUnits.QuadPart = 100; pResultCB->AvailableAllocationUnits.QuadPart = 0; @@ -5231,21 +5231,32 @@ RDR_GetVolumeSizeInfo( IN cm_user_t *userp, } volType = cm_VolumeType(volp, scp->fid.volume); - Name = volName; - OfflineMsg = offLineMsg; - MOTD = motd; - lock_ReleaseWrite(&scp->rw); - do { - code = cm_ConnFromFID(&scp->fid, userp, &req, &connp); - if (code) continue; - - rxconnp = cm_GetRxConn(connp); - code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume, - &volStat, &Name, &OfflineMsg, &MOTD); - rx_PutConnection(rxconnp); - - } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, code)); - code = cm_MapRPCError(code, &req); + + code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ, + CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + if (code == 0) + { + sync_done = 1; + + Name = volName; + OfflineMsg = offLineMsg; + MOTD = motd; + lock_ReleaseWrite(&scp->rw); + scp_locked = 0; + + do { + code = cm_ConnFromFID(&scp->fid, userp, &req, &connp); + if (code) continue; + + rxconnp = cm_GetRxConn(connp); + code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume, + &volStat, &Name, &OfflineMsg, &MOTD); + rx_PutConnection(rxconnp); + + } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, code)); + code = cm_MapRPCError(code, &req); + } + if (code == 0) { if (volStat.MaxQuota) { @@ -5271,18 +5282,27 @@ RDR_GetVolumeSizeInfo( IN cm_user_t *userp, } } } else { - + /* + * Lie about the available space. Out of quota errors will need + * detected when the file server rejects the store data. + */ pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF; pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000; code = 0; } - lock_ObtainWrite(&scp->rw); - } - cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + if (sync_done) { + if (!scp_locked) { + lock_ObtainWrite(&scp->rw); + scp_locked = 1; + } + cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); + } + } _done: - lock_ReleaseWrite(&scp->rw); + if (scp_locked) + lock_ReleaseWrite(&scp->rw); if (volp) cm_PutVolume(volp); cm_ReleaseSCache(scp); -- 2.39.5