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 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; }
static NTSTATUS SrvBuildOpenState( PSRV_EXEC_CONTEXT pExecContext, POPEN_REQUEST_HEADER pRequestHeader, PWSTR pwszFilename, PSRV_OPEN_STATE_SMB_V1* ppOpenState ) { NTSTATUS ntStatus = STATUS_SUCCESS; PLWIO_SRV_CONNECTION pConnection = pExecContext->pConnection; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V1 pCtxSmb1 = pCtxProtocol->pSmb1Context; PSRV_OPEN_STATE_SMB_V1 pOpenState = NULL; ntStatus = SrvAllocateMemory( sizeof(SRV_OPEN_STATE_SMB_V1), (PVOID*)&pOpenState); BAIL_ON_NT_STATUS(ntStatus); pOpenState->refCount = 1; pthread_mutex_init(&pOpenState->mutex, NULL); pOpenState->pMutex = &pOpenState->mutex; pOpenState->stage = SRV_OPEN_STAGE_SMB_V1_INITIAL; // TODO: Handle root fids ntStatus = SrvAllocateMemory( sizeof(IO_FILE_NAME), (PVOID*)&pOpenState->pFilename); BAIL_ON_NT_STATUS(ntStatus); pOpenState->pTree = SrvTreeAcquire(pCtxSmb1->pTree); ntStatus = SrvBuildTreeRelativePath( pCtxSmb1->pTree, pwszFilename, pOpenState->pFilename); BAIL_ON_NT_STATUS(ntStatus); pOpenState->pwszFilename = pwszFilename; ntStatus = IoRtlEcpListAllocate(&pOpenState->pEcpList); BAIL_ON_NT_STATUS(ntStatus); ntStatus = IoRtlEcpListInsert(pOpenState->pEcpList, SRV_ECP_TYPE_NET_OPEN_INFO, &pOpenState->networkOpenInfo, sizeof(pOpenState->networkOpenInfo), NULL); BAIL_ON_NT_STATUS(ntStatus); /* For named pipes, we need to pipe some extra data into the npfs driver: * - Session key * - Client principal name * - Client address */ if (SrvTreeIsNamedPipe(pCtxSmb1->pTree)) { ntStatus = SrvConnectionGetNamedPipeSessionKey( pConnection, pOpenState->pEcpList); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvConnectionGetNamedPipeClientAddress( pConnection, pOpenState->pEcpList); BAIL_ON_NT_STATUS(ntStatus); ntStatus = IoRtlEcpListInsert(pOpenState->pEcpList, SRV_ECP_TYPE_PIPE_INFO, &pOpenState->filePipeInfo, sizeof(pOpenState->filePipeInfo), NULL); BAIL_ON_NT_STATUS(ntStatus); ntStatus = IoRtlEcpListInsert(pOpenState->pEcpList, SRV_ECP_TYPE_PIPE_LOCAL_INFO, &pOpenState->filePipeLocalInfo, sizeof(pOpenState->filePipeLocalInfo), NULL); BAIL_ON_NT_STATUS(ntStatus); } pOpenState->usCreateOptions = FILE_NON_DIRECTORY_FILE; pOpenState->usShareAccess = (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE); switch (pRequestHeader->usDesiredAccess & 0x70) { case 0x00: /* compatibility mode */ ntStatus = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntStatus); break; case 0x10: /* deny read/write/execute (exclusive) */ pOpenState->usShareAccess &= (USHORT)~FILE_SHARE_READ; pOpenState->usShareAccess &= (USHORT)~FILE_SHARE_WRITE; break; case 0x20: /* deny write */ pOpenState->usShareAccess &= (USHORT)~FILE_SHARE_WRITE; break; case 0x30: /* deny read/execute */ pOpenState->usShareAccess &= (USHORT)~FILE_SHARE_READ; break; case 0x40: /* deny none */ break; } /* desired access mask */ switch (pRequestHeader->usDesiredAccess & 0x7) { case 0x00: pOpenState->ulDesiredAccessMask = GENERIC_READ; break; case 0x01: pOpenState->ulDesiredAccessMask = GENERIC_WRITE; break; case 0x02: pOpenState->ulDesiredAccessMask = GENERIC_READ | GENERIC_WRITE; break; case 0x03: pOpenState->ulDesiredAccessMask = (GENERIC_READ | GENERIC_EXECUTE); break; default: ntStatus = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntStatus); break; } /* action to take if the file exists */ switch (pRequestHeader->usOpenFunction) { case 0x0000: /* Weird EXECUTE -> OPEN_IF semantics */ if ((pOpenState->ulDesiredAccessMask & GENERIC_EXECUTE) == 0) { ntStatus = STATUS_INVALID_DISPOSITION; BAIL_ON_NT_STATUS(ntStatus); } pOpenState->ulCreateDisposition = FILE_OPEN_IF; break; case 0x0001: /* Open file */ pOpenState->ulCreateDisposition = FILE_OPEN; break; case 0x0002: /* truncate file */ pOpenState->ulCreateDisposition = FILE_OVERWRITE; break; case 0x0010: /* create new file */ pOpenState->ulCreateDisposition = FILE_CREATE; break; case 0x0011: /* open or create file */ pOpenState->ulCreateDisposition = FILE_OPEN_IF; break; case 0x0012: /* create or truncate */ pOpenState->ulCreateDisposition = FILE_OVERWRITE_IF; break; default: ntStatus = STATUS_INVALID_DISPOSITION; BAIL_ON_NT_STATUS(ntStatus); break; } pOpenState->pRequestHeader = pRequestHeader; *ppOpenState = pOpenState; cleanup: return ntStatus; error: *ppOpenState = NULL; if (pOpenState) { SrvFreeOpenState(pOpenState); } 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; }