static NTSTATUS SrvRenameFile( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = 0; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V1 pCtxSmb1 = pCtxProtocol->pSmb1Context; PSRV_TRANS2_STATE_SMB_V1 pTrans2State = NULL; pTrans2State = (PSRV_TRANS2_STATE_SMB_V1)pCtxSmb1->hState; if (!pTrans2State->pData2) { ntStatus = SrvUnmarshalRenameInformation(pExecContext); BAIL_ON_NT_STATUS(ntStatus); } if (pTrans2State->pRootDir) { ((PFILE_RENAME_INFORMATION)pTrans2State->pData2)->RootDirectory = pTrans2State->pRootDir->hFile; } else if (!pTrans2State->hDir) { wchar16_t wszBackSlash[] = { '\\', 0 }; PFILE_RENAME_INFORMATION pRenameInfo = (PFILE_RENAME_INFORMATION)pTrans2State->pData2; if (*pRenameInfo->FileName == wszBackSlash[0]) { ntStatus = STATUS_NOT_SUPPORTED; } else if (pTrans2State->pFile) { ntStatus = SrvGetParentPath( &pTrans2State->pFile->pFilename->Name, &pTrans2State->dirPath.Name); } else if (pTrans2State->hFile) { ntStatus = SrvGetParentPath( &pTrans2State->fileName.Name, &pTrans2State->dirPath.Name); } else { ntStatus = STATUS_INVALID_PARAMETER; } BAIL_ON_NT_STATUS(ntStatus); pTrans2State->dirPath.RootFileHandle = pTrans2State->pTree->hFile; // Catch failed CreateFile calls when they come back around ntStatus = pTrans2State->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); SrvPrepareTrans2StateAsync(pTrans2State, pExecContext); ntStatus = SrvIoCreateFile( pTrans2State->pTree->pShareInfo, &pTrans2State->hDir, pTrans2State->pAcb, &pTrans2State->ioStatusBlock, pCtxSmb1->pSession->pIoSecurityContext, &pTrans2State->dirPath, pTrans2State->pSecurityDescriptor, pTrans2State->pSecurityQOS, GENERIC_READ, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, /* EA Buffer */ 0, /* EA Length */ pTrans2State->pEcpList ); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseTrans2StateAsync(pTrans2State); // completed synchronously } if (!pTrans2State->pRootDir) { ((PFILE_RENAME_INFORMATION)pTrans2State->pData2)->RootDirectory = pTrans2State->hDir; } if (!pTrans2State->bSetInfoAttempted) { pTrans2State->bSetInfoAttempted = TRUE; SrvPrepareTrans2StateAsync(pTrans2State, pExecContext); ntStatus = IoSetInformationFile( (pTrans2State->pFile ? pTrans2State->pFile->hFile : pTrans2State->hFile), pTrans2State->pAcb, &pTrans2State->ioStatusBlock, (PFILE_RENAME_INFORMATION)pTrans2State->pData2, pTrans2State->usBytesAllocated, FileRenameInformation); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseTrans2StateAsync(pTrans2State); // completed synchronously } error: return ntStatus; }
NTSTATUS SrvProcessOpenAndX( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = 0; PLWIO_SRV_CONNECTION pConnection = pExecContext->pConnection; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V1 pCtxSmb1 = pCtxProtocol->pSmb1Context; PLWIO_SRV_SESSION pSession = NULL; PLWIO_SRV_TREE pTree = NULL; PSRV_OPEN_STATE_SMB_V1 pOpenState = NULL; BOOLEAN bInLock = FALSE; pOpenState = (PSRV_OPEN_STATE_SMB_V1)pCtxSmb1->hState; if (pOpenState) { InterlockedIncrement(&pOpenState->refCount); } else { ULONG iMsg = pCtxSmb1->iMsg; PSRV_MESSAGE_SMB_V1 pSmbRequest = &pCtxSmb1->pRequests[iMsg]; PBYTE pBuffer = pSmbRequest->pBuffer + pSmbRequest->usHeaderSize; ULONG ulOffset = pSmbRequest->usHeaderSize; ULONG ulBytesAvailable = pSmbRequest->ulMessageSize - pSmbRequest->usHeaderSize; POPEN_REQUEST_HEADER pRequestHeader = NULL; // Do not free PWSTR pwszFilename = NULL; // Do not free if (pCtxSmb1->pFile) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = SrvConnectionFindSession_SMB_V1( pCtxSmb1, pConnection, pSmbRequest->pHeader->uid, &pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSetStatSessionInfo(pExecContext, pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSessionFindTree_SMB_V1( pCtxSmb1, pSession, pSmbRequest->pHeader->tid, &pTree); BAIL_ON_NT_STATUS(ntStatus); ntStatus = WireUnmarshallOpenRequest( pBuffer, ulBytesAvailable, ulOffset, &pRequestHeader, &pwszFilename); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvBuildOpenState( pExecContext, pRequestHeader, pwszFilename, &pOpenState); BAIL_ON_NT_STATUS(ntStatus); pCtxSmb1->hState = pOpenState; InterlockedIncrement(&pOpenState->refCount); pCtxSmb1->pfnStateRelease = &SrvReleaseOpenStateHandle; } LWIO_LOCK_MUTEX(bInLock, &pOpenState->mutex); switch (pOpenState->stage) { case SRV_OPEN_STAGE_SMB_V1_INITIAL: SRV_LOG_CALL_DEBUG( pExecContext->pLogContext, SMB_PROTOCOL_VERSION_1, pCtxSmb1->pRequests[pCtxSmb1->iMsg].pHeader->command, &SrvLogOpenState_SMB_V1, pOpenState); pOpenState->stage = SRV_OPEN_STAGE_SMB_V1_OPEN_FILE_COMPLETED; SrvPrepareOpenStateAsync(pOpenState, pExecContext); ntStatus = SrvIoCreateFile( pOpenState->pTree->pShareInfo, &pOpenState->hFile, pOpenState->pAcb, &pOpenState->ioStatusBlock, pSession->pIoSecurityContext, pOpenState->pFilename, pOpenState->pSecurityDescriptor, pOpenState->pSecurityQOS, pOpenState->ulDesiredAccessMask, pOpenState->pRequestHeader->ulAllocationSize, pOpenState->pRequestHeader->usFileAttributes, pOpenState->usShareAccess, pOpenState->ulCreateDisposition, pOpenState->usCreateOptions, NULL, /* EA Buffer */ 0, /* EA Length */ pOpenState->pEcpList); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseOpenStateAsync(pOpenState); // completed synchronously // intentional fall through case SRV_OPEN_STAGE_SMB_V1_OPEN_FILE_COMPLETED: ntStatus = pOpenState->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); pOpenState->ulCreateAction = pOpenState->ioStatusBlock.CreateResult; ntStatus = SrvTreeCreateFile( pOpenState->pTree, pOpenState->pwszFilename, &pOpenState->hFile, &pOpenState->pFilename, pOpenState->pRequestHeader->usDesiredAccess, pOpenState->pRequestHeader->ulAllocationSize, pOpenState->pRequestHeader->usFileAttributes, pOpenState->usShareAccess, pOpenState->ulCreateDisposition, pOpenState->usCreateOptions, &pOpenState->pFile); BAIL_ON_NT_STATUS(ntStatus); pOpenState->pFile->pfnCancelAsyncOperationsFile = SrvCancelFileAsyncOperations; pOpenState->stage = SRV_OPEN_STAGE_SMB_V1_ATTEMPT_QUERY_INFO; // intentional fall through case SRV_OPEN_STAGE_SMB_V1_ATTEMPT_QUERY_INFO: ntStatus = SrvQueryFileOpenInformation(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pOpenState->stage = SRV_OPEN_STAGE_SMB_V1_REQUEST_OPLOCK; // intentional fall through case SRV_OPEN_STAGE_SMB_V1_REQUEST_OPLOCK: ntStatus = SrvRequestOpenXOplocks(pExecContext); // Don't fail on the account on not being granted an oplock pOpenState->stage = SRV_OPEN_STAGE_SMB_V1_QUERY_INFO_COMPLETED; // intentional fall through case SRV_OPEN_STAGE_SMB_V1_QUERY_INFO_COMPLETED: ntStatus = pOpenState->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); if (!pOpenState->pFile->hCancellableBRLStateList) { PSRV_BYTE_RANGE_LOCK_STATE_LIST pBRLStateList = NULL; ntStatus = SrvCreatePendingLockStateList(&pBRLStateList); BAIL_ON_NT_STATUS(ntStatus); pOpenState->pFile->hCancellableBRLStateList = (HANDLE)pBRLStateList; pOpenState->pFile->pfnFreeBRLStateList = &SrvFreePendingLockStateListHandle; } ntStatus = SrvBuildOpenResponse(pExecContext); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvElementsRegisterResource( &pOpenState->pFile->resource, NULL); BAIL_ON_NT_STATUS(ntStatus); pOpenState->stage = SRV_OPEN_STAGE_SMB_V1_DONE; // intentional fall through case SRV_OPEN_STAGE_SMB_V1_DONE: if (pOpenState->pRequestHeader->usDesiredAccess & FILE_READ_DATA) { pOpenState->pFile->ulPermissions |= SRV_PERM_FILE_READ; } if (pOpenState->pRequestHeader->usDesiredAccess & FILE_WRITE_DATA) { pOpenState->pFile->ulPermissions |= SRV_PERM_FILE_WRITE; } if (pOpenState->ulCreateAction == FILE_CREATED) { pOpenState->pFile->ulPermissions |= SRV_PERM_FILE_CREATE; } // transfer file so we do not run it down pCtxSmb1->pFile = pOpenState->pFile; pOpenState->pFile = NULL; break; } cleanup: if (pTree) { SrvTreeRelease(pTree); } if (pSession) { SrvSessionRelease(pSession); } if (pOpenState) { LWIO_UNLOCK_MUTEX(bInLock, &pOpenState->mutex); SrvReleaseOpenState(pOpenState); } return ntStatus; error: switch (ntStatus) { case STATUS_PENDING: // TODO: Add an indicator to the file object to trigger a // cleanup if the connection gets closed and all the // files involved have to be closed break; default: if (pOpenState) { SrvReleaseOpenStateAsync(pOpenState); } break; } goto cleanup; }
NTSTATUS SrvProcessTrans2SetPathInformation( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = 0; PLWIO_SRV_CONNECTION pConnection = pExecContext->pConnection; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V1 pCtxSmb1 = pCtxProtocol->pSmb1Context; ULONG iMsg = pCtxSmb1->iMsg; PSRV_MESSAGE_SMB_V1 pSmbRequest = &pCtxSmb1->pRequests[iMsg]; PSRV_TRANS2_STATE_SMB_V1 pTrans2State = NULL; ACCESS_MASK accessMask = 0; pTrans2State = (PSRV_TRANS2_STATE_SMB_V1)pCtxSmb1->hState; switch (pTrans2State->stage) { case SRV_TRANS2_STAGE_SMB_V1_INITIAL: ntStatus = SrvUnmarshallSetPathInfoParams( pTrans2State->pParameters, pTrans2State->pRequestHeader->parameterCount, &pTrans2State->pSmbInfoLevel, &pTrans2State->pwszFilename); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvConnectionFindSession_SMB_V1( pCtxSmb1, pConnection, pSmbRequest->pHeader->uid, &pTrans2State->pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSetStatSessionInfo( pExecContext, pTrans2State->pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSessionFindTree_SMB_V1( pCtxSmb1, pTrans2State->pSession, pSmbRequest->pHeader->tid, &pTrans2State->pTree); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvBuildTreeRelativePath( pTrans2State->pTree, pTrans2State->pwszFilename, &pTrans2State->fileName); BAIL_ON_NT_STATUS(ntStatus); pTrans2State->stage = SRV_TRANS2_STAGE_SMB_V1_CREATE_FILE_COMPLETED; SrvPrepareTrans2StateAsync(pTrans2State, pExecContext); accessMask = SrvGetPathAccessMask(pExecContext); ntStatus = SrvIoCreateFile( pTrans2State->pTree->pShareInfo, &pTrans2State->hFile, pTrans2State->pAcb, &pTrans2State->ioStatusBlock, pTrans2State->pSession->pIoSecurityContext, &pTrans2State->fileName, pTrans2State->pSecurityDescriptor, pTrans2State->pSecurityQOS, accessMask, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0, NULL, /* EA Buffer */ 0, /* EA Length */ pTrans2State->pEcpList ); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseTrans2StateAsync(pTrans2State); // completed synchronously // intentional fall through case SRV_TRANS2_STAGE_SMB_V1_CREATE_FILE_COMPLETED: pTrans2State->stage = SRV_TRANS2_STAGE_SMB_V1_ATTEMPT_IO; // intentional fall through case SRV_TRANS2_STAGE_SMB_V1_ATTEMPT_IO: ntStatus = pTrans2State->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSetPathInfo(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pTrans2State->stage = SRV_TRANS2_STAGE_SMB_V1_IO_COMPLETE; // intentional fall through case SRV_TRANS2_STAGE_SMB_V1_IO_COMPLETE: ntStatus = pTrans2State->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); pTrans2State->stage = SRV_TRANS2_STAGE_SMB_V1_BUILD_RESPONSE; // intentional fall through case SRV_TRANS2_STAGE_SMB_V1_BUILD_RESPONSE: ntStatus = SrvBuildSetInfoResponse(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pTrans2State->stage = SRV_TRANS2_STAGE_SMB_V1_DONE; // intentional fall through case SRV_TRANS2_STAGE_SMB_V1_DONE: break; default: ntStatus = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(ntStatus); break; } cleanup: return ntStatus; error: goto cleanup; }
static NTSTATUS SrvExecuteRename( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = 0; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V1 pCtxSmb1 = pCtxProtocol->pSmb1Context; PSRV_RENAME_STATE_SMB_V1 pRenameState = NULL; pRenameState = (PSRV_RENAME_STATE_SMB_V1)pCtxSmb1->hState; ntStatus = pRenameState->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); if (!pRenameState->hDir) { SrvPrepareRenameStateAsync(pRenameState, pExecContext); ntStatus = SrvIoCreateFile( pCtxSmb1->pTree->pShareInfo, &pRenameState->hDir, pRenameState->pAcb, &pRenameState->ioStatusBlock, pCtxSmb1->pSession->pIoSecurityContext, &pRenameState->dirPath, pRenameState->pSecurityDescriptor, pRenameState->pSecurityQOS, GENERIC_READ, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, /* EA Buffer */ 0, /* EA Length */ pRenameState->pDirEcpList ); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseRenameStateAsync(pRenameState); // completed synchronously } if (!pRenameState->hFile) { SrvPrepareRenameStateAsync(pRenameState, pExecContext); ntStatus = SrvIoCreateFile( pCtxSmb1->pTree->pShareInfo, &pRenameState->hFile, pRenameState->pAcb, &pRenameState->ioStatusBlock, pCtxSmb1->pSession->pIoSecurityContext, &pRenameState->oldName, pRenameState->pSecurityDescriptor, pRenameState->pSecurityQOS, DELETE, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, 0, NULL, /* EA Buffer */ 0, /* EA Length */ pRenameState->pFileEcpList ); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseRenameStateAsync(pRenameState); // completed synchronously } if (!pRenameState->pFileRenameInfo) { pRenameState->ulDataLen = sizeof(FILE_RENAME_INFORMATION) + wc16slen(pRenameState->newName.FileName) * sizeof(wchar16_t); ntStatus = SrvAllocateMemory( pRenameState->ulDataLen, (PVOID*)&pRenameState->pData); BAIL_ON_NT_STATUS(ntStatus); pRenameState->pFileRenameInfo = (PFILE_RENAME_INFORMATION)pRenameState->pData; pRenameState->pFileRenameInfo->ReplaceIfExists = FALSE; pRenameState->pFileRenameInfo->RootDirectory = pRenameState->hDir; pRenameState->pFileRenameInfo->FileNameLength = wc16slen(pRenameState->newName.FileName) * sizeof(wchar16_t); memcpy( (PBYTE)pRenameState->pFileRenameInfo->FileName, (PBYTE)pRenameState->newName.FileName, pRenameState->pFileRenameInfo->FileNameLength); SrvPrepareRenameStateAsync(pRenameState, pExecContext); ntStatus = IoSetInformationFile( pRenameState->hFile, pRenameState->pAcb, &pRenameState->ioStatusBlock, pRenameState->pFileRenameInfo, pRenameState->ulDataLen, FileRenameInformation); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseRenameStateAsync(pRenameState); // completed synchronously } cleanup: return ntStatus; error: goto cleanup; }
NTSTATUS SrvFinderCreateSearchSpace( IN IO_FILE_HANDLE hRootFileHandle, IN PSRV_SHARE_INFO pShareInfo, IN PIO_CREATE_SECURITY_CONTEXT pIoSecurityContext, IN HANDLE hFinderRepository, IN PWSTR pwszFilesystemPath, IN PWSTR pwszSearchPattern, IN SMB_FILE_ATTRIBUTES usSearchAttrs, IN USHORT usFlags, IN ULONG ulSearchStorageType, IN SMB_INFO_LEVEL infoLevel, IN BOOLEAN bUseLongFilenames, IN ACCESS_MASK accessMask, OUT PHANDLE phFinder, OUT PUSHORT pusSearchId ) { NTSTATUS ntStatus = 0; IO_FILE_HANDLE hFile = NULL; IO_STATUS_BLOCK ioStatusBlock = {0}; IO_FILE_NAME fileName = {0}; PVOID pSecurityDescriptor = NULL; PVOID pSecurityQOS = NULL; PSRV_FINDER_REPOSITORY pFinderRepository = NULL; PSRV_SEARCH_SPACE pSearchSpace = NULL; USHORT usCandidateSearchId = 0; BOOLEAN bFound = FALSE; BOOLEAN bInLock = FALSE; PIO_ECP_LIST pEcpList = NULL; FILE_CREATE_OPTIONS createOptions = 0; pFinderRepository = (PSRV_FINDER_REPOSITORY)hFinderRepository; fileName.RootFileHandle = hRootFileHandle; ntStatus = LwRtlUnicodeStringInitEx(&fileName.Name, pwszFilesystemPath); BAIL_ON_NT_STATUS(ntStatus); if (pShareInfo->Flags & SHARE_INFO_FLAG_ABE_ENABLED) { ntStatus = IoRtlEcpListAllocate(&pEcpList); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvIoPrepareAbeEcpList(pEcpList); BAIL_ON_NT_STATUS(ntStatus); } if (usFlags & SMB_FIND_WITH_BACKUP_INTENT) { createOptions |= FILE_OPEN_FOR_BACKUP_INTENT; } ntStatus = SrvIoCreateFile( pShareInfo, &hFile, NULL, &ioStatusBlock, pIoSecurityContext, &fileName, pSecurityDescriptor, pSecurityQOS, accessMask, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, createOptions, NULL, /* EA Buffer */ 0, /* EA Length */ pEcpList); BAIL_ON_NT_STATUS(ntStatus); LWIO_LOCK_MUTEX(bInLock, &pFinderRepository->mutex); usCandidateSearchId = pFinderRepository->usNextSearchId; do { PSRV_SEARCH_SPACE pSearchSpace = NULL; // 0 is not a valid search id if (!usCandidateSearchId || (usCandidateSearchId == UINT16_MAX)) { usCandidateSearchId = 1; } ntStatus = LwRtlRBTreeFind( pFinderRepository->pSearchSpaceCollection, &usCandidateSearchId, (PVOID*)&pSearchSpace); if (ntStatus == STATUS_NOT_FOUND) { ntStatus = STATUS_SUCCESS; bFound = TRUE; } else { usCandidateSearchId++; } BAIL_ON_NT_STATUS(ntStatus); } while ((usCandidateSearchId != pFinderRepository->usNextSearchId) && !bFound); if (!bFound) { ntStatus = STATUS_TOO_MANY_OPENED_FILES; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = SrvAllocateMemory( sizeof(SRV_SEARCH_SPACE), (PVOID*)&pSearchSpace); BAIL_ON_NT_STATUS(ntStatus); pSearchSpace->refCount = 1; pthread_mutex_init(&pSearchSpace->mutex, NULL); pSearchSpace->pMutex = &pSearchSpace->mutex; pSearchSpace->usSearchId = usCandidateSearchId; ntStatus = LwRtlRBTreeAdd( pFinderRepository->pSearchSpaceCollection, &pSearchSpace->usSearchId, pSearchSpace); BAIL_ON_NT_STATUS(ntStatus); pSearchSpace->hFile = hFile; hFile = NULL; pSearchSpace->infoLevel = infoLevel; pSearchSpace->usSearchAttrs = usSearchAttrs; pSearchSpace->ulSearchStorageType = ulSearchStorageType; pSearchSpace->bUseLongFilenames = bUseLongFilenames; ntStatus = SrvAllocateStringW( pwszSearchPattern, &pSearchSpace->pwszSearchPattern); BAIL_ON_NT_STATUS(ntStatus); InterlockedIncrement(&pSearchSpace->refCount); pFinderRepository->usNextSearchId = usCandidateSearchId + 1; *phFinder = pSearchSpace; *pusSearchId = usCandidateSearchId; cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pFinderRepository->mutex); if (pEcpList) { IoRtlEcpListFree(&pEcpList); } return ntStatus; error: *phFinder = NULL; *pusSearchId = 0; if (pSearchSpace) { SrvFinderReleaseSearchSpace(pSearchSpace); } if (hFile) { IoCloseFile(hFile); } goto cleanup; }
NTSTATUS SrvProcessCheckDirectory( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = 0; PLWIO_SRV_CONNECTION pConnection = pExecContext->pConnection; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V1 pCtxSmb1 = pCtxProtocol->pSmb1Context; PLWIO_SRV_SESSION pSession = NULL; PLWIO_SRV_TREE pTree = NULL; PSRV_CHECKDIR_STATE_SMB_V1 pCheckdirState = NULL; BOOLEAN bInLock = FALSE; pCheckdirState = (PSRV_CHECKDIR_STATE_SMB_V1)pCtxSmb1->hState; if (pCheckdirState) { InterlockedIncrement(&pCheckdirState->refCount); } else { ULONG iMsg = pCtxSmb1->iMsg; PSRV_MESSAGE_SMB_V1 pSmbRequest = &pCtxSmb1->pRequests[iMsg]; PBYTE pBuffer = pSmbRequest->pBuffer + pSmbRequest->usHeaderSize; ULONG ulOffset = pSmbRequest->usHeaderSize; ULONG ulBytesAvailable = pSmbRequest->ulMessageSize - pSmbRequest->usHeaderSize; PWSTR pwszPathFragment = NULL; // Do not free PSMB_CHECK_DIRECTORY_REQUEST_HEADER pRequestHeader = NULL;// Do not free ntStatus = SrvConnectionFindSession_SMB_V1( pCtxSmb1, pConnection, pSmbRequest->pHeader->uid, &pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSetStatSessionInfo(pExecContext, pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSessionFindTree_SMB_V1( pCtxSmb1, pSession, pSmbRequest->pHeader->tid, &pTree); BAIL_ON_NT_STATUS(ntStatus); ntStatus = WireUnmarshallCheckDirectoryRequest( pBuffer, ulBytesAvailable, ulOffset, &pRequestHeader, &pwszPathFragment); BAIL_ON_NT_STATUS(ntStatus); if (!pwszPathFragment || !*pwszPathFragment) { ntStatus = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = SrvBuildCheckdirState( pRequestHeader, pwszPathFragment, &pCheckdirState); BAIL_ON_NT_STATUS(ntStatus); pCtxSmb1->hState = pCheckdirState; InterlockedIncrement(&pCheckdirState->refCount); pCtxSmb1->pfnStateRelease = &SrvReleaseCheckdirStateHandle; } LWIO_LOCK_MUTEX(bInLock, &pCheckdirState->mutex); switch (pCheckdirState->stage) { case SRV_CHECKDIR_STAGE_SMB_V1_INITIAL: SRV_LOG_CALL_DEBUG( pExecContext->pLogContext, SMB_PROTOCOL_VERSION_1, pCtxSmb1->pRequests[pCtxSmb1->iMsg].pHeader->command, &SrvLogCheckDirState_SMB_V1, pCheckdirState); ntStatus = SrvBuildTreeRelativePath( pCtxSmb1->pTree, pCheckdirState->pwszPathFragment, &pCheckdirState->fileName); BAIL_ON_NT_STATUS(ntStatus); pCheckdirState->stage = SRV_CHECKDIR_STAGE_SMB_V1_ATTEMPT_CHECK; // Intentional fall through case SRV_CHECKDIR_STAGE_SMB_V1_ATTEMPT_CHECK: // Catch failed CreateFile calls when they come back around ntStatus = pCheckdirState->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); if (!pCheckdirState->hFile) { SrvPrepareCheckdirStateAsync(pCheckdirState, pExecContext); ntStatus = SrvIoCreateFile( pCtxSmb1->pTree->pShareInfo, &pCheckdirState->hFile, pCheckdirState->pAcb, &pCheckdirState->ioStatusBlock, pCtxSmb1->pSession->pIoSecurityContext, &pCheckdirState->fileName, pCheckdirState->pSecurityDescriptor, pCheckdirState->pSecurityQOS, FILE_LIST_DIRECTORY, 0, /* allocation size */ FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, /* EA Buffer */ 0, /* EA Length */ pCheckdirState->pEcpList); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseCheckdirStateAsync(pCheckdirState); // completed sync } pCheckdirState->stage = SRV_CHECKDIR_STAGE_SMB_V1_BUILD_RESPONSE; // intentional fall through case SRV_CHECKDIR_STAGE_SMB_V1_BUILD_RESPONSE: ntStatus = pCheckdirState->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvBuildCheckDirectoryResponse(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pCheckdirState->stage = SRV_CHECKDIR_STAGE_SMB_V1_DONE; // intentional fall through case SRV_CHECKDIR_STAGE_SMB_V1_DONE: break; } cleanup: if (pTree) { SrvTreeRelease(pTree); } if (pSession) { SrvSessionRelease(pSession); } if (pCheckdirState) { LWIO_UNLOCK_MUTEX(bInLock, &pCheckdirState->mutex); SrvReleaseCheckdirState(pCheckdirState); } return ntStatus; error: switch (ntStatus) { case STATUS_PENDING: // TODO: Add an indicator to the file object to trigger a // cleanup if the connection gets closed and all the // files involved have to be closed break; default: if (pCheckdirState) { SrvReleaseCheckdirStateAsync(pCheckdirState); } break; } goto cleanup; }
static NTSTATUS SrvDeleteSingleFile( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V1 pCtxSmb1 = pCtxProtocol->pSmb1Context; PSRV_DELETE_STATE_SMB_V1 pDeleteState = NULL; wchar16_t wszDot[] = {'.', 0}; pDeleteState = (PSRV_DELETE_STATE_SMB_V1)pCtxSmb1->hState; if (!pDeleteState->bPendingCreate) { if ((SMBWc16sCmp(pDeleteState->pwszSearchPattern2, wszDot) == 0)) { ntStatus = STATUS_OBJECT_NAME_INVALID; BAIL_ON_NT_STATUS(ntStatus); } ntStatus = SrvBuildFilePath( pDeleteState->pwszFilesystemPath, pDeleteState->pwszSearchPattern2, &pDeleteState->fileName.Name); BAIL_ON_NT_STATUS(ntStatus); pDeleteState->fileName.RootFileHandle = pDeleteState->pTree->hFile; SrvPrepareDeleteStateAsync(pDeleteState, pExecContext); pDeleteState->bPendingCreate = TRUE; ntStatus = SrvIoCreateFile( pDeleteState->pTree->pShareInfo, &pDeleteState->hFile, pDeleteState->pAcb, &pDeleteState->ioStatusBlock, pDeleteState->pSession->pIoSecurityContext, &pDeleteState->fileName, pDeleteState->pSecurityDescriptor, pDeleteState->pSecurityQOS, DELETE, 0, FILE_ATTRIBUTE_NORMAL, FILE_NO_SHARE, FILE_OPEN, FILE_DELETE_ON_CLOSE|FILE_NON_DIRECTORY_FILE, NULL, 0, pDeleteState->pEcpList); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseDeleteStateAsync(pDeleteState); // completed sync } pDeleteState->bPendingCreate = FALSE; ntStatus = pDeleteState->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); if (pDeleteState->hFile) { IoCloseFile(pDeleteState->hFile); pDeleteState->hFile = NULL; } cleanup: return ntStatus; error: /* Have to do some error mapping here to match WinXP */ switch (ntStatus) { case STATUS_PENDING: case STATUS_ACCESS_DENIED: case STATUS_FILE_IS_A_DIRECTORY: case STATUS_SHARING_VIOLATION: case STATUS_OBJECT_NAME_INVALID: break; case STATUS_OBJECT_NAME_NOT_FOUND: case STATUS_NO_SUCH_FILE: ntStatus = STATUS_OBJECT_NAME_NOT_FOUND; break; default: ntStatus = STATUS_CANNOT_DELETE; break; } goto cleanup; }
static NTSTATUS SrvDeleteFiles( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V1 pCtxSmb1 = pCtxProtocol->pSmb1Context; PSRV_DELETE_STATE_SMB_V1 pDeleteState = NULL; PWSTR pwszFilename = NULL; wchar16_t wszDot[] = {'.', 0}; pDeleteState = (PSRV_DELETE_STATE_SMB_V1)pCtxSmb1->hState; if (pDeleteState->bPendingCreate) { pDeleteState->bPendingCreate = FALSE; ntStatus = pDeleteState->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); IoCloseFile(pDeleteState->hFile); pDeleteState->hFile = NULL; pDeleteState->bDeletedFile = TRUE; pDeleteState->iResult++; } for (;;) { for ( ; pDeleteState->iResult < pDeleteState->usSearchResultCount; pDeleteState->iResult++) { BOOLEAN bEligibleForDelete = FALSE; FILE_ATTRIBUTES ulIncludeAttributes = 0; if (!pDeleteState->pResult) { pDeleteState->pResult = (PSMB_FIND_FILE_BOTH_DIRECTORY_INFO_HEADER)pDeleteState->pData; } else if (pDeleteState->pResult->NextEntryOffset) { PBYTE pTmp = (PBYTE)pDeleteState->pResult + pDeleteState->pResult->NextEntryOffset; pDeleteState->pResult = (PSMB_FIND_FILE_BOTH_DIRECTORY_INFO_HEADER)pTmp; } else { ntStatus = STATUS_INTERNAL_ERROR; BAIL_ON_NT_STATUS(ntStatus); } if (pwszFilename) { SrvFreeMemory(pwszFilename); pwszFilename = NULL; } ulIncludeAttributes = SMB_FILE_ATTRIBUTES_TO_NATIVE(pDeleteState->usSearchAttributes); bEligibleForDelete = (IsSetFlag(pDeleteState->pResult->FileAttributes, ulIncludeAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))) || (!IsSetFlag(pDeleteState->pResult->FileAttributes, (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))); if (!bEligibleForDelete) { if (!pDeleteState->bPathHasWildCards) { if ((SMBWc16sCmp(pDeleteState->pwszSearchPattern2, wszDot) == 0)) { ntStatus = STATUS_OBJECT_NAME_INVALID; } else if (IsSetFlag(pDeleteState->pResult->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) { ntStatus = STATUS_FILE_IS_A_DIRECTORY; } else { ntStatus = STATUS_NO_SUCH_FILE; } BAIL_ON_NT_STATUS(ntStatus); } continue; } if (pDeleteState->bUseLongFilenames) { ntStatus = SrvAllocateMemory( pDeleteState->pResult->FileNameLength + sizeof(wchar16_t), (PVOID*)&pwszFilename); BAIL_ON_NT_STATUS(ntStatus); memcpy((PBYTE)pwszFilename, (PBYTE)pDeleteState->pResult->FileName, pDeleteState->pResult->FileNameLength); } else { ntStatus = SrvAllocateMemory( pDeleteState->pResult->ShortNameLength + sizeof(wchar16_t), (PVOID*)&pwszFilename); BAIL_ON_NT_STATUS(ntStatus); memcpy((PBYTE)pwszFilename, (PBYTE)pDeleteState->pResult->ShortName, pDeleteState->pResult->ShortNameLength); } if (SMBWc16sCmp(pwszFilename, wszDot) == 0) { ntStatus = STATUS_OBJECT_NAME_INVALID; BAIL_ON_NT_STATUS(ntStatus); } SRV_FREE_UNICODE_STRING(&pDeleteState->fileName.Name); ntStatus = SrvBuildFilePath( pDeleteState->pwszFilesystemPath, pwszFilename, &pDeleteState->fileName.Name); BAIL_ON_NT_STATUS(ntStatus); pDeleteState->fileName.RootFileHandle = pDeleteState->pTree->hFile; SrvPrepareDeleteStateAsync(pDeleteState, pExecContext); pDeleteState->bPendingCreate = TRUE; ntStatus = SrvIoCreateFile( pDeleteState->pTree->pShareInfo, &pDeleteState->hFile, pDeleteState->pAcb, &pDeleteState->ioStatusBlock, pDeleteState->pSession->pIoSecurityContext, &pDeleteState->fileName, pDeleteState->pSecurityDescriptor, pDeleteState->pSecurityQOS, DELETE, 0, FILE_ATTRIBUTE_NORMAL, FILE_NO_SHARE, FILE_OPEN, FILE_DELETE_ON_CLOSE|FILE_NON_DIRECTORY_FILE, NULL, 0, pDeleteState->pEcpList); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseDeleteStateAsync(pDeleteState); // completed sync pDeleteState->bPendingCreate = FALSE; IoCloseFile(pDeleteState->hFile); pDeleteState->hFile = NULL; pDeleteState->bDeletedFile = TRUE; } if (pDeleteState->bEndOfSearch) { break; } if (pDeleteState->pData) { SrvFreeMemory(pDeleteState->pData); pDeleteState->pData = NULL; } pDeleteState->iResult = 0; pDeleteState->pResult = NULL; ntStatus = SrvFinderGetSearchResults( pDeleteState->hSearchSpace, FALSE, /* bReturnSingleEntry */ FALSE, /* bRestartScan */ 10, /* Desired search count */ UINT16_MAX, /* Max data count */ pDeleteState->usDataOffset, &pDeleteState->pData, &pDeleteState->usDataLen, &pDeleteState->usSearchResultCount, &pDeleteState->bEndOfSearch); if (ntStatus == STATUS_NO_MORE_MATCHES) { ntStatus = STATUS_ASSERTION_FAILURE; BAIL_ON_NT_STATUS(ntStatus); } if (ntStatus == STATUS_NO_SUCH_FILE) { ntStatus = STATUS_SUCCESS; break; } } if (!pDeleteState->bDeletedFile) { if (pDeleteState->bPathHasWildCards) { ntStatus = STATUS_NO_SUCH_FILE; } else { ntStatus = STATUS_OBJECT_NAME_NOT_FOUND; } BAIL_ON_NT_STATUS(ntStatus); } cleanup: if (pwszFilename) { SrvFreeMemory(pwszFilename); } return ntStatus; error: /* Have to do some error mapping here to match WinXP */ switch (ntStatus) { case STATUS_PENDING: case STATUS_ACCESS_DENIED: case STATUS_FILE_IS_A_DIRECTORY: case STATUS_SHARING_VIOLATION: case STATUS_OBJECT_NAME_NOT_FOUND: case STATUS_OBJECT_NAME_INVALID: case STATUS_NO_SUCH_FILE: break; default: ntStatus = STATUS_CANNOT_DELETE; break; } goto cleanup; }