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; }
NTSTATUS SrvProcessLogoffAndX( 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_MESSAGE_SMB_V1 pSmbResponse = &pCtxSmb1->pResponses[iMsg]; PLOGOFF_RESPONSE_HEADER pResponseHeader = NULL; // Do not free PBYTE pOutBuffer = pSmbResponse->pBuffer; ULONG ulBytesAvailable = pSmbResponse->ulBytesAvailable; ULONG ulOffset = 0; ULONG ulTotalBytesUsed = 0; PLWIO_SRV_SESSION pSession = NULL; ntStatus = SrvConnectionFindSession( pConnection, pSmbRequest->pHeader->uid, &pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSetStatSessionInfo(pExecContext, pSession); BAIL_ON_NT_STATUS(ntStatus); SRV_LOG_DEBUG( pExecContext->pLogContext, SMB_PROTOCOL_VERSION_1, pSmbRequest->pHeader->command, "Logging off session: command(%u),uid(%u),mid(%u),pid(%u),tid(%u)", pSmbRequest->pHeader->command, pSmbRequest->pHeader->uid, pSmbRequest->pHeader->mid, SMB_V1_GET_PROCESS_ID(pSmbRequest->pHeader), pSmbRequest->pHeader->tid); SrvSessionRundown(pSession); if (!pSmbResponse->ulSerialNum) { ntStatus = SrvMarshalHeader_SMB_V1( pOutBuffer, ulOffset, ulBytesAvailable, COM_LOGOFF_ANDX, STATUS_SUCCESS, TRUE, pConnection->serverProperties.Capabilities, pSmbRequest->pHeader->tid, SMB_V1_GET_PROCESS_ID(pSmbRequest->pHeader), pSmbRequest->pHeader->uid, pSmbRequest->pHeader->mid, pConnection->serverProperties.bRequireSecuritySignatures, &pSmbResponse->pHeader, &pSmbResponse->pWordCount, &pSmbResponse->pAndXHeader, &pSmbResponse->usHeaderSize); } else { ntStatus = SrvMarshalHeaderAndX_SMB_V1( pOutBuffer, ulOffset, ulBytesAvailable, COM_LOGOFF_ANDX, &pSmbResponse->pWordCount, &pSmbResponse->pAndXHeader, &pSmbResponse->usHeaderSize); } BAIL_ON_NT_STATUS(ntStatus); pOutBuffer += pSmbResponse->usHeaderSize; ulOffset += pSmbResponse->usHeaderSize; ulBytesAvailable -= pSmbResponse->usHeaderSize; ulTotalBytesUsed += pSmbResponse->usHeaderSize; *pSmbResponse->pWordCount = 2; if (ulBytesAvailable < sizeof(LOGOFF_RESPONSE_HEADER)) { ntStatus = STATUS_INVALID_BUFFER_SIZE; BAIL_ON_NT_STATUS(ntStatus); } pResponseHeader = (PLOGOFF_RESPONSE_HEADER)pOutBuffer; // pOutBuffer += sizeof(LOGOFF_RESPONSE_HEADER); // ulOffset += sizeof(LOGOFF_RESPONSE_HEADER); // ulBytesAvailable -= sizeof(LOGOFF_RESPONSE_HEADER); ulTotalBytesUsed += sizeof(LOGOFF_RESPONSE_HEADER); pResponseHeader->byteCount = 0; pSmbResponse->ulMessageSize = ulTotalBytesUsed; cleanup: if (pSession) { SrvSessionRelease(pSession); } return ntStatus; error: if (ulTotalBytesUsed) { pSmbResponse->pHeader = NULL; pSmbResponse->pAndXHeader = NULL; memset(pSmbResponse->pBuffer, 0, ulTotalBytesUsed); } pSmbResponse->ulMessageSize = 0; goto cleanup; }
NTSTATUS SrvProcessTrans2QueryFileInformation( 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; pTrans2State = (PSRV_TRANS2_STATE_SMB_V1)pCtxSmb1->hState; switch (pTrans2State->stage) { case SRV_TRANS2_STAGE_SMB_V1_INITIAL: ntStatus = SrvUnmarshallQueryFileInfoParams( pTrans2State->pParameters, pTrans2State->pRequestHeader->parameterCount, &pTrans2State->usFid, &pTrans2State->pSmbInfoLevel); 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 = SrvTreeFindFile_SMB_V1( pCtxSmb1, pTrans2State->pTree, pTrans2State->usFid, &pTrans2State->pFile); BAIL_ON_NT_STATUS(ntStatus); pTrans2State->stage = SRV_TRANS2_STAGE_SMB_V1_ATTEMPT_IO; // intentional fall through case SRV_TRANS2_STAGE_SMB_V1_ATTEMPT_IO: ntStatus = SrvQueryInfo(pExecContext); 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 = SrvBuildQueryInfoResponse(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; }
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 SrvProcessRename( 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_RENAME_STATE_SMB_V1 pRenameState = NULL; BOOLEAN bInLock = FALSE; pRenameState = (PSRV_RENAME_STATE_SMB_V1)pCtxSmb1->hState; if (pRenameState) { InterlockedIncrement(&pRenameState->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; PSMB_RENAME_REQUEST_HEADER pRequestHeader = NULL; // Do not free PWSTR pwszOldName = NULL; // Do not free PWSTR pwszNewName = 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 = WireUnmarshallRenameRequest( pBuffer, ulBytesAvailable, ulOffset, &pRequestHeader, &pwszOldName, &pwszNewName); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvBuildRenameState( pRequestHeader, pwszOldName, pwszNewName, &pRenameState); BAIL_ON_NT_STATUS(ntStatus); pCtxSmb1->hState = pRenameState; InterlockedIncrement(&pRenameState->refCount); pCtxSmb1->pfnStateRelease = &SrvReleaseRenameStateHandle; } LWIO_LOCK_MUTEX(bInLock, &pRenameState->mutex); switch (pRenameState->stage) { case SRV_RENAME_STAGE_SMB_V1_INITIAL: ntStatus = SrvBuildTreeRelativePath( pCtxSmb1->pTree, pRenameState->pwszOldName, &pRenameState->oldName); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvBuildTreeRelativePath( pCtxSmb1->pTree, NULL, &pRenameState->dirPath); BAIL_ON_NT_STATUS(ntStatus); pRenameState->newName.FileName = pRenameState->pwszNewName; pRenameState->stage = SRV_RENAME_STAGE_SMB_V1_ATTEMPT_RENAME; // intentional fall through case SRV_RENAME_STAGE_SMB_V1_ATTEMPT_RENAME: ntStatus = SrvExecuteRename(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pRenameState->stage = SRV_RENAME_STAGE_SMB_V1_BUILD_RESPONSE; // intentional fall through case SRV_RENAME_STAGE_SMB_V1_BUILD_RESPONSE: ntStatus = SrvBuildRenameResponse(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pRenameState->stage = SRV_RENAME_STAGE_SMB_V1_DONE; // intentional fall through case SRV_RENAME_STAGE_SMB_V1_DONE: break; } cleanup: if (pSession) { SrvSessionRelease(pSession); } if (pTree) { SrvTreeRelease(pTree); } if (pRenameState) { LWIO_UNLOCK_MUTEX(bInLock, &pRenameState->mutex); SrvReleaseRenameState(pRenameState); } 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 (pRenameState) { SrvReleaseRenameStateAsync(pRenameState); } break; } 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; }
NTSTATUS SrvProcessDelete( 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_DELETE_STATE_SMB_V1 pDeleteState = NULL; BOOLEAN bInLock = FALSE; pDeleteState = (PSRV_DELETE_STATE_SMB_V1)pCtxSmb1->hState; if (pDeleteState) { InterlockedIncrement(&pDeleteState->refCount); } else { PBYTE pBuffer = pSmbRequest->pBuffer + pSmbRequest->usHeaderSize; ULONG ulOffset = pSmbRequest->usHeaderSize; ULONG ulBytesAvailable = pSmbRequest->ulMessageSize - pSmbRequest->usHeaderSize; PSMB_DELETE_REQUEST_HEADER pRequestHeader = NULL; // Do not free PWSTR pwszSearchPattern = NULL; // Do not free BOOLEAN bUseLongFilenames = FALSE; ntStatus = WireUnmarshallDeleteRequest( pBuffer, ulBytesAvailable, ulOffset, &pRequestHeader, &pwszSearchPattern); BAIL_ON_NT_STATUS(ntStatus); if (!pwszSearchPattern || !*pwszSearchPattern) { ntStatus = STATUS_CANNOT_DELETE; BAIL_ON_NT_STATUS(ntStatus); } if (pSmbRequest->pHeader->flags2 & FLAG2_KNOWS_LONG_NAMES) { bUseLongFilenames = TRUE; } ntStatus = SrvBuildDeleteState( pRequestHeader, pwszSearchPattern, bUseLongFilenames, &pDeleteState); BAIL_ON_NT_STATUS(ntStatus); pCtxSmb1->hState = pDeleteState; InterlockedIncrement(&pDeleteState->refCount); pCtxSmb1->pfnStateRelease = &SrvReleaseDeleteStateHandle; } LWIO_LOCK_MUTEX(bInLock, &pDeleteState->mutex); switch (pDeleteState->stage) { case SRV_DELETE_STAGE_SMB_V1_INITIAL: SRV_LOG_CALL_DEBUG( pExecContext->pLogContext, SMB_PROTOCOL_VERSION_1, pCtxSmb1->pRequests[pCtxSmb1->iMsg].pHeader->command, &SrvLogDeleteState_SMB_V1, pDeleteState); ntStatus = SrvConnectionFindSession_SMB_V1( pCtxSmb1, pConnection, pSmbRequest->pHeader->uid, &pDeleteState->pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSetStatSessionInfo( pExecContext, pDeleteState->pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSessionFindTree_SMB_V1( pCtxSmb1, pDeleteState->pSession, pSmbRequest->pHeader->tid, &pDeleteState->pTree); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvFinderBuildSearchPath( NULL, pDeleteState->pwszSearchPattern, &pDeleteState->pwszFilesystemPath, &pDeleteState->pwszSearchPattern2, &pDeleteState->bPathHasWildCards); BAIL_ON_NT_STATUS(ntStatus); // Need to treat as wildcard if either one of hidden or system // was not specified. if (!(IsSetFlag(pDeleteState->usSearchAttributes, SMB_FILE_ATTRIBUTE_HIDDEN) && IsSetFlag(pDeleteState->usSearchAttributes, SMB_FILE_ATTRIBUTE_SYSTEM))) { pDeleteState->bNeedSearchAttributes = TRUE; } if (pDeleteState->bPathHasWildCards || pDeleteState->bNeedSearchAttributes) { SMB_FILE_ATTRIBUTES usSearchAttributes = pDeleteState->usSearchAttributes; // Only the hidden and system inclusive attributes are // consulted for delete -- except that, apparently, // SMB_FILE_ATTRIBUTE_DIRECTORY can also be used, but will // result in an error. usSearchAttributes &= SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_DIRECTORY; ntStatus = SrvFinderCreateSearchSpace( pDeleteState->pTree->hFile, pDeleteState->pTree->pShareInfo, pDeleteState->pSession->pIoSecurityContext, pDeleteState->pSession->hFinderRepository, pDeleteState->pwszFilesystemPath, pDeleteState->pwszSearchPattern2, usSearchAttributes, 0, 0, // ulSearchStorageType SMB_FIND_FILE_BOTH_DIRECTORY_INFO, pDeleteState->bUseLongFilenames, FILE_LIST_DIRECTORY, &pDeleteState->hSearchSpace, &pDeleteState->usSearchId); BAIL_ON_NT_STATUS(ntStatus); } pDeleteState->stage = SRV_DELETE_STAGE_SMB_V1_DELETE_FILES; // intentional fall through case SRV_DELETE_STAGE_SMB_V1_DELETE_FILES: if (pDeleteState->hSearchSpace) { ntStatus = SrvDeleteFiles(pExecContext); } else { ntStatus = SrvDeleteSingleFile(pExecContext); } BAIL_ON_NT_STATUS(ntStatus); pDeleteState->stage = SRV_DELETE_STAGE_SMB_V1_BUILD_RESPONSE; // intentional fall through case SRV_DELETE_STAGE_SMB_V1_BUILD_RESPONSE: ntStatus = SrvBuildDeleteResponse(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pDeleteState->stage = SRV_DELETE_STAGE_SMB_V1_DONE; // intentional fall through case SRV_DELETE_STAGE_SMB_V1_DONE: break; } cleanup: if (pDeleteState) { LWIO_UNLOCK_MUTEX(bInLock, &pDeleteState->mutex); SrvReleaseDeleteState(pDeleteState); } 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 (pDeleteState) { SrvReleaseDeleteStateAsync(pDeleteState); } break; } goto cleanup; }