VOID RdrNotifyContextList( PLW_LIST_LINKS pList, BOOLEAN bLocked, pthread_mutex_t* pMutex, NTSTATUS status, PVOID pParam ) { LW_LIST_LINKS List; PLW_LIST_LINKS pLink = NULL; BOOLEAN bWasLocked = bLocked; LWIO_LOCK_MUTEX(bLocked, pMutex); LwListInit(&List); while ((pLink = LwListRemoveHead(pList))) { LwListInsertTail(&List, pLink); } LWIO_UNLOCK_MUTEX(bLocked, pMutex); RdrContinueContextList(&List, status, pParam); LWIO_LOCK_MUTEX(bLocked, pMutex); while ((pLink = LwListRemoveHead(&List))) { LwListInsertTail(pList, pLink); } if (!bWasLocked) { LWIO_UNLOCK_MUTEX(bLocked, pMutex); } }
VOID SrvCancelChangeNotify_SMB_V2( PLWIO_ASYNC_STATE pAsyncState ) { BOOLEAN bInLock = FALSE; PSRV_NOTIFY_STATE_SMB_V2 pNotifyState = (PSRV_NOTIFY_STATE_SMB_V2)pAsyncState->hAsyncState; LWIO_LOCK_MUTEX(bInLock, &pNotifyState->mutex); SrvCancelNotifyState_SMB_V2_inlock(pNotifyState); LWIO_UNLOCK_MUTEX(bInLock, &pNotifyState->mutex); }
VOID SrvNotifyStateCancel( HANDLE hNotifyState ) { BOOLEAN bInLock = FALSE; PSRV_CHANGE_NOTIFY_STATE_SMB_V1 pNotifyState = (PSRV_CHANGE_NOTIFY_STATE_SMB_V1)hNotifyState; LWIO_LOCK_MUTEX(bInLock, &pNotifyState->mutex); SrvNotifyStateCancel_inlock(pNotifyState); LWIO_UNLOCK_MUTEX(bInLock, &pNotifyState->mutex); }
NTSTATUS PvfsZctCompleteRead( IN PPVFS_IRP_CONTEXT pIrpContext ) { PPVFS_ZCT_CONTEXT pZctContext = (PPVFS_ZCT_CONTEXT) pIrpContext->pIrp->Args.ReadWrite.ZctCompletionContext; PPVFS_CCB pCcb = pZctContext->pCcb; BOOLEAN bMutexLocked = FALSE; LWIO_LOCK_MUTEX(bMutexLocked, &pCcb->FileMutex); PvfsFreeZctContext(&pZctContext); LWIO_UNLOCK_MUTEX(bMutexLocked, &pCcb->FileMutex); return STATUS_SUCCESS; }
BOOLEAN PvfsIrpContextCheckFlag( PPVFS_IRP_CONTEXT pIrpContext, USHORT BitToCheck ) { BOOLEAN bLocked = FALSE; BOOLEAN bIsSet = FALSE; LWIO_LOCK_MUTEX(bLocked, &pIrpContext->Mutex); bIsSet = IsSetFlag(pIrpContext->Flags, BitToCheck); LWIO_UNLOCK_MUTEX(bLocked, &pIrpContext->Mutex); return bIsSet; }
static VOID SrvCancelNotifyState_SMB_V2( HANDLE hNotifyState ) { BOOLEAN bInLock = FALSE; PSRV_NOTIFY_STATE_SMB_V2 pNotifyState = (PSRV_NOTIFY_STATE_SMB_V2)hNotifyState; LWIO_LOCK_MUTEX(bInLock, &pNotifyState->mutex); SrvCancelNotifyState_SMB_V2_inlock(pNotifyState); LWIO_UNLOCK_MUTEX(bInLock, &pNotifyState->mutex); }
VOID RdrSwapDomainHints( PLW_HASHMAP* ppMap ) { PLW_HASHMAP pExisting = NULL; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &gRdrRuntime.Lock); pExisting = gRdrRuntime.pDomainHints; gRdrRuntime.pDomainHints = *ppMap; LWIO_UNLOCK_MUTEX(bLocked, &gRdrRuntime.Lock); *ppMap = pExisting; }
NTSTATUS SrvElementsGetBootTime( PULONG64 pullBootTime ) { LONG64 llBootTime = 0LL; BOOLEAN bInLock = FALSE; LWIO_LOCK_MUTEX(bInLock, &gSrvElements.mutex); llBootTime = gSrvElements.llBootTime; LWIO_UNLOCK_MUTEX(bInLock, &gSrvElements.mutex); *pullBootTime = llBootTime; return STATUS_SUCCESS; }
LW_NTSTATUS LwIoGetActiveCreds( IN OPTIONAL LW_PUNICODE_STRING PathPrefix, OUT LW_PIO_CREDS* ppToken ) { NTSTATUS Status = STATUS_SUCCESS; PIO_PATH_CREDS pPathCreds = NULL; PIO_CREDS pCreds = NULL; BOOL bInLock = FALSE; Status = LwIoGetThreadCreds(&pCreds); BAIL_ON_NT_STATUS(Status); if (!pCreds && PathPrefix) { LWIO_LOCK_MUTEX(bInLock, &gLock); Status = LwIoFindPathCreds(PathPrefix, FALSE, &pPathCreds); BAIL_ON_NT_STATUS(Status); if (pPathCreds) { Status = LwIoCopyCreds(pPathCreds->pCreds, &pCreds); BAIL_ON_NT_STATUS(Status); } } if (!pCreds && gpProcessCreds) { Status = LwIoCopyCreds(gpProcessCreds, &pCreds); BAIL_ON_NT_STATUS(Status); } *ppToken = pCreds; error: LWIO_UNLOCK_MUTEX(bInLock, &gLock); return Status; }
static VOID PvfsNotifyFullReportBuffer( PPVFS_FCB pFcb, PPVFS_FCB pReportParentFcb, PPVFS_NOTIFY_REPORT_RECORD pReport ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PLW_LIST_LINKS pFilterLink = NULL; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); for (pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, NULL); pFilterLink; pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, pFilterLink)) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); /* Match the filter and depth */ if ((pFilter->NotifyFilter & pReport->Filter) && ((pFcb == pReportParentFcb) || pFilter->bWatchTree)) { ntError = PvfsNotifyReportBuffer( &pFilter->Buffer, pReport->Action, pReport->pszFilename); break; } } LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); return; }
NTSTATUS SrvFinderGetSearchSpace( IN HANDLE hFinderRepository, IN USHORT usSearchId, OUT PHANDLE phFinder ) { NTSTATUS ntStatus = 0; PSRV_FINDER_REPOSITORY pFinderRepository = NULL; PSRV_SEARCH_SPACE pSearchSpace = NULL; BOOLEAN bInLock = FALSE; pFinderRepository = (PSRV_FINDER_REPOSITORY)hFinderRepository; LWIO_LOCK_MUTEX(bInLock, &pFinderRepository->mutex); ntStatus = LwRtlRBTreeFind( pFinderRepository->pSearchSpaceCollection, &usSearchId, (PVOID*)&pSearchSpace); BAIL_ON_NT_STATUS(ntStatus); InterlockedIncrement(&pSearchSpace->refCount); *phFinder = pSearchSpace; cleanup: LWIO_UNLOCK_MUTEX(bInLock, &pFinderRepository->mutex); return ntStatus; error: *phFinder = NULL; goto cleanup; }
static VOID SrvExecuteRenameAsyncCB( PVOID pContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSRV_EXEC_CONTEXT pExecContext = (PSRV_EXEC_CONTEXT)pContext; PSRV_PROTOCOL_EXEC_CONTEXT pProtocolContext = pExecContext->pProtocolContext; PSRV_RENAME_STATE_SMB_V1 pRenameState = NULL; BOOLEAN bInLock = FALSE; pRenameState = (PSRV_RENAME_STATE_SMB_V1)pProtocolContext->pSmb1Context->hState; LWIO_LOCK_MUTEX(bInLock, &pRenameState->mutex); if (pRenameState->pAcb->AsyncCancelContext) { IoDereferenceAsyncCancelContext( &pRenameState->pAcb->AsyncCancelContext); } pRenameState->pAcb = NULL; LWIO_UNLOCK_MUTEX(bInLock, &pRenameState->mutex); ntStatus = SrvProdConsEnqueue(gProtocolGlobals_SMB_V1.pWorkQueue, pContext); if (ntStatus != STATUS_SUCCESS) { LWIO_LOG_ERROR("Failed to enqueue execution context [status:0x%x]", ntStatus); SrvReleaseExecContext(pExecContext); } }
VOID SrvShareDbReleaseContext( PSRV_SHARE_DB_CONTEXT pDbContext ) { BOOLEAN bInLock = FALSE; PSRV_SHARE_DB_GLOBALS pGlobals = &gShareRepository_lwshare; LWIO_LOCK_MUTEX(bInLock, &pGlobals->mutex); if (pGlobals->ulNumDbContexts < pGlobals->ulMaxNumDbContexts) { SrvShareDbFreeContext(pDbContext); } else { pDbContext->pNext = pGlobals->pDbContextList; pGlobals->pDbContextList = pDbContext; pGlobals->ulNumDbContexts++; } LWIO_UNLOCK_MUTEX(bInLock, &pGlobals->mutex); }
BOOLEAN RdrProcessNegotiateResponse2( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SOCKET pSocket = pContext->State.TreeConnect.pSocket; PSMB_PACKET pPacket = pParam; BOOLEAN bFreeContext = FALSE; BOOLEAN bSocketLocked = FALSE; PRDR_SMB2_NEGOTIATE_RESPONSE_HEADER pHeader = NULL; PBYTE pNegHint = NULL; ULONG ulNegHintLength = 0; BAIL_ON_NT_STATUS(status); status = pPacket->pSMB2Header->error; BAIL_ON_NT_STATUS(status); LWIO_LOCK_MUTEX(bSocketLocked, &pSocket->mutex); status = RdrSmb2DecodeNegotiateResponse( pPacket, &pHeader, &pNegHint, &ulNegHintLength); BAIL_ON_NT_STATUS(status); pSocket->ulMaxTransactSize = pHeader->ulMaxTransactionSize; pSocket->ulMaxReadSize = pHeader->ulMaxReadSize; pSocket->ulMaxWriteSize = pHeader->ulMaxWriteSize; pSocket->capabilities = pHeader->ulCapabilities; pSocket->ucSecurityMode = pHeader->ucSecurityMode; pSocket->securityBlobLen = ulNegHintLength; status = LwIoAllocateMemory( pSocket->securityBlobLen, (PVOID *) &pSocket->pSecurityBlob); BAIL_ON_NT_STATUS(status); memcpy(pSocket->pSecurityBlob, pNegHint, pSocket->securityBlobLen); status = RdrSocketSetProtocol(pSocket, SMB_PROTOCOL_VERSION_2); BAIL_ON_NT_STATUS(status); pSocket->state = RDR_SOCKET_STATE_READY; RdrNotifyContextList( &pSocket->StateWaiters, bSocketLocked, &pSocket->mutex, STATUS_SUCCESS, pSocket); LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrNegotiateComplete2(pContext, STATUS_SUCCESS, pSocket); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); cleanup: LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } RdrFreePacket(pPacket); return FALSE; error: if (status != STATUS_PENDING && pSocket) { LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrSocketInvalidate(pSocket, status); RdrSocketRelease(pSocket); } goto cleanup; }
static BOOLEAN RdrSessionSetupComplete2( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SESSION2 pSession = pParam; PRDR_TREE2 pTree = NULL; BOOLEAN bTreeLocked = FALSE; BOOLEAN bFreeContext = FALSE; BAIL_ON_NT_STATUS(status); status = RdrTree2FindOrCreate( &pSession, pContext->State.TreeConnect.pwszSharename, &pTree); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pTree2 = pTree; LWIO_LOCK_MUTEX(bTreeLocked, &pTree->mutex); switch (pTree->state) { case RDR_TREE_STATE_NOT_READY: pTree->state = RDR_TREE_STATE_INITIALIZING; pContext->Continue = RdrFinishTreeConnect2; status = RdrTransceiveTreeConnect2(pContext, pTree, pTree->pwszPath); BAIL_ON_NT_STATUS(status); break; case RDR_TREE_STATE_INITIALIZING: pContext->Continue = RdrTreeConnect2Complete; LwListInsertTail(&pTree->StateWaiters, &pContext->Link); bFreeContext = TRUE; status = STATUS_PENDING; break; case RDR_TREE_STATE_READY: RdrTreeConnect2Complete(pContext, status, pTree); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_TREE_STATE_ERROR: status = pTree->error; BAIL_ON_NT_STATUS(status); break; } cleanup: LWIO_UNLOCK_MUTEX(bTreeLocked, &pTree->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } return FALSE; error: if (status != STATUS_PENDING && pTree) { LWIO_UNLOCK_MUTEX(bTreeLocked, &pTree->mutex); RdrTree2Invalidate(pTree, status); RdrTree2Release(pTree); } if (status != STATUS_PENDING && pSession) { RdrSession2Release(pSession); } goto cleanup; }
static NTSTATUS RdrTree2FindOrCreate( IN OUT PRDR_SESSION2* ppSession, IN PCWSTR pwszPath, OUT PRDR_TREE2* ppTree ) { NTSTATUS ntStatus = 0; PRDR_TREE2 pTree = NULL; BOOLEAN bInLock = FALSE; PRDR_SESSION2 pSession = *ppSession; LWIO_LOCK_MUTEX(bInLock, &pSession->mutex); ntStatus = SMBHashGetValue( pSession->pTreeHashByPath, pwszPath, (PVOID *) &pTree); if (!ntStatus) { pTree->refCount++; RdrTree2Revive(pTree); RdrSession2Release(pSession); *ppSession = NULL; } else { ntStatus = RdrTree2Create(&pTree); BAIL_ON_NT_STATUS(ntStatus); pTree->pSession = pSession; ntStatus = RtlWC16StringDuplicate( &pTree->pwszPath, pwszPath); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SMBHashSetValue( pSession->pTreeHashByPath, pTree->pwszPath, pTree); BAIL_ON_NT_STATUS(ntStatus); pTree->bParentLink = TRUE; *ppSession = NULL; } LWIO_UNLOCK_MUTEX(bInLock, &pSession->mutex); *ppTree = pTree; cleanup: return ntStatus; error: LWIO_UNLOCK_MUTEX(bInLock, &pSession->mutex); *ppTree = NULL; if (pTree) { RdrTree2Release(pTree); } goto cleanup; }
static VOID RdrNegotiateGssContextWorkItem2( PVOID pParam ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContext = pParam; PRDR_SESSION2 pSession = pContext->State.TreeConnect.pSession2; PRDR_SOCKET pSocket = pSession->pSocket; PSMB_PACKET pPacket = pContext->State.TreeConnect.pPacket; PBYTE pInBlob = NULL; DWORD dwInBlobLength = 0; PBYTE pOutBlob = NULL; DWORD dwOutBlobLength = 0; BOOLEAN bSessionLocked = FALSE; if (pPacket) { /* Capture session id */ if (pSession->ullSessionId == 0) { pSession->ullSessionId = pPacket->pSMB2Header->ullSessionId; } else if (pSession->ullSessionId != pPacket->pSMB2Header->ullSessionId) { status = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(status); } status = RdrSmb2DecodeSessionSetupResponse( pPacket, NULL, &pInBlob, &dwInBlobLength); BAIL_ON_NT_STATUS(status); } else { pInBlob = pSession->pSocket->pSecurityBlob; dwInBlobLength = pSession->pSocket->securityBlobLen; } if (pContext->State.TreeConnect.pszCachePath) { status = SMBKrb5SetDefaultCachePath( pContext->State.TreeConnect.pszCachePath, NULL); BAIL_ON_NT_STATUS(status); } if (!pContext->State.TreeConnect.hGssContext) { status = SMBGSSContextBuild( pSocket->pwszCanonicalName, pContext->State.TreeConnect.pCreds, &pContext->State.TreeConnect.hGssContext); BAIL_ON_NT_STATUS(status); } status = SMBGSSContextNegotiate( pContext->State.TreeConnect.hGssContext, pInBlob, dwInBlobLength, &pOutBlob, &dwOutBlobLength); BAIL_ON_NT_STATUS(status); if (!SMBGSSContextNegotiateComplete(pContext->State.TreeConnect.hGssContext)) { pContext->Continue = RdrProcessSessionSetupResponse2; status = RdrTransceiveSessionSetup2( pContext, pSession, pOutBlob, dwOutBlobLength); BAIL_ON_NT_STATUS(status); } else { LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); status = SMBGSSContextGetSessionKey( pContext->State.TreeConnect.hGssContext, &pSession->pSessionKey, &pSession->dwSessionKeyLength); BAIL_ON_NT_STATUS(status); if (!pSocket->pSessionKey && pSession->pSessionKey) { status = LwIoAllocateMemory( pSession->dwSessionKeyLength, OUT_PPVOID(&pSocket->pSessionKey)); BAIL_ON_NT_STATUS(status); memcpy(pSocket->pSessionKey, pSession->pSessionKey, pSession->dwSessionKeyLength); pSocket->dwSessionKeyLength = pSession->dwSessionKeyLength; } status = RdrSocketAddSession2ById(pSocket, pSession); BAIL_ON_NT_STATUS(status); pSession->state = RDR_SESSION_STATE_READY; RdrNotifyContextList( &pSession->StateWaiters, bSessionLocked, &pSession->mutex, status, pSession); LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete2(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RTL_FREE(&pOutBlob); if (status != STATUS_PENDING) { if (pSession) { RdrSession2Invalidate(pSession, status); RdrSession2Release(pSession); } RdrSessionSetupComplete2(pContext, status, NULL); } return; error: goto cleanup; }
static BOOLEAN RdrProcessSessionSetupResponse2( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SESSION2 pSession = pContext->State.TreeConnect.pSession2; PSMB_PACKET pPacket = pParam; BOOLEAN bSessionLocked = FALSE; BOOLEAN bFreeContext = FALSE; BAIL_ON_NT_STATUS(status); LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); if (pPacket) { status = pPacket->pSMB2Header->error; if (status == STATUS_MORE_PROCESSING_REQUIRED) { status = STATUS_SUCCESS; } BAIL_ON_NT_STATUS(status); pSession->ullSessionId = pPacket->pSMB2Header->ullSessionId; } /* Save the packet on the context for RdrNegotiateGssContextWorkItem2 */ pContext->State.TreeConnect.pPacket = pPacket; pPacket = NULL; /* Dispatch a work item to negotiate the GSS context in a separate thread. Because GSS-API could potentially block in a network call (KRB5) or an IPC call (NTLM), calling into it directly from the socket task could cause a deadlock. */ status = LwRtlQueueWorkItem( gRdrRuntime.pThreadPool, RdrNegotiateGssContextWorkItem2, pContext, 0); BAIL_ON_NT_STATUS(status); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } RdrFreePacket(pPacket); return FALSE; error: if (status != STATUS_PENDING && pSession) { LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSession2Invalidate(pSession, status); RdrSession2Release(pSession); } goto cleanup; }
BOOLEAN RdrNegotiateComplete2( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SOCKET pSocket = pParam; PRDR_SESSION2 pSession = NULL; BOOLEAN bSessionLocked = FALSE; BOOLEAN bFreeContext = FALSE; PIO_CREDS pCreds = pContext->State.TreeConnect.pCreds; BAIL_ON_NT_STATUS(status); if (pContext->State.TreeConnect.bStopOnDfs && pSocket->capabilities & RDR_SMB2_CAP_DFS) { status = STATUS_DFS_EXIT_PATH_FOUND; BAIL_ON_NT_STATUS(status); } status = RdrSession2FindOrCreate( &pSocket, pContext->State.TreeConnect.pCreds, pContext->State.TreeConnect.Uid, &pSession); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pSession2 = pSession; LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); switch (pSession->state) { case RDR_SESSION_STATE_NOT_READY: pSession->state = RDR_SESSION_STATE_INITIALIZING; switch (pCreds->type) { case IO_CREDS_TYPE_KRB5_TGT: status = SMBCredTokenToKrb5CredCache( pCreds, &pContext->State.TreeConnect.pszCachePath); BAIL_ON_NT_STATUS(status); break; case IO_CREDS_TYPE_PLAIN: break; default: status = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(status); } LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrProcessSessionSetupResponse2(pContext, STATUS_SUCCESS, NULL); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_INITIALIZING: pContext->Continue = RdrSessionSetupComplete2; LwListInsertTail(&pSession->StateWaiters, &pContext->Link); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_READY: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete2(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_ERROR: status = pSession->error; BAIL_ON_NT_STATUS(status); break; } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } return FALSE; error: if (status != STATUS_PENDING && pSession) { LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSession2Invalidate(pSession, status); } RdrSession2Release(pSession); } if (status != STATUS_PENDING && pSocket) { if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSocketInvalidate(pSocket, status); } RdrSocketRelease(pSocket); } goto cleanup; }
LW_NTSTATUS LwIoSetPathCreds( IN LW_PUNICODE_STRING PathPrefix, IN OPTIONAL LW_PIO_CREDS pCreds ) { LW_NTSTATUS Status = STATUS_SUCCESS; PIO_PATH_CREDS pPathCreds = NULL; PIO_CREDS pCredCopy = NULL; BOOL bInLock = FALSE; LWIO_LOCK_MUTEX(bInLock, &gLock); Status = LwIoFindPathCreds(PathPrefix, TRUE, &pPathCreds); BAIL_ON_NT_STATUS(Status); if (pPathCreds) { Status = LwIoCopyCreds(pCreds, &pCredCopy); BAIL_ON_NT_STATUS(Status); if (pPathCreds->pCreds) { LwIoDeleteCreds(pPathCreds->pCreds); } pPathCreds->pCreds = pCredCopy; pCredCopy = NULL; pPathCreds = NULL; } else if (pCreds) { Status = RTL_ALLOCATE(&pPathCreds, IO_PATH_CREDS, sizeof(IO_PATH_CREDS)); BAIL_ON_NT_STATUS(Status); LwListInit(&pPathCreds->link); Status = LwIoNormalizePath(PathPrefix, &pPathCreds->PathPrefix); BAIL_ON_NT_STATUS(Status); Status = LwIoCopyCreds(pCreds, &pPathCreds->pCreds); BAIL_ON_NT_STATUS(Status); LwListInsertBefore(&gPathCreds, &pPathCreds->link); pPathCreds = NULL; } cleanup: LWIO_UNLOCK_MUTEX(bInLock, &gLock); if (pCredCopy) { LwIoDeleteCreds(pCredCopy); } if (pPathCreds) { LwIoDeletePathCreds(pPathCreds); } return Status; error: goto cleanup; }
NTSTATUS SrvProcessFlush_SMB_V2( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PLWIO_SRV_CONNECTION pConnection = pExecContext->pConnection; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V2 pCtxSmb2 = pCtxProtocol->pSmb2Context; PSRV_FLUSH_STATE_SMB_V2 pFlushState = NULL; PLWIO_SRV_SESSION_2 pSession = NULL; PLWIO_SRV_TREE_2 pTree = NULL; PLWIO_SRV_FILE_2 pFile = NULL; BOOLEAN bInLock = FALSE; pFlushState = (PSRV_FLUSH_STATE_SMB_V2)pCtxSmb2->hState; if (pFlushState) { InterlockedIncrement(&pFlushState->refCount); } else { ULONG iMsg = pCtxSmb2->iMsg; PSRV_MESSAGE_SMB_V2 pSmbRequest = &pCtxSmb2->pRequests[iMsg]; PSMB2_FID pFid = NULL; // Do not free ntStatus = SrvConnection2FindSession_SMB_V2( pCtxSmb2, pConnection, pSmbRequest->pHeader->ullSessionId, &pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSetStatSession2Info(pExecContext, pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSession2FindTree_SMB_V2( pCtxSmb2, pSession, pSmbRequest->pHeader->ulTid, &pTree); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SMB2UnmarshalFlushRequest(pSmbRequest, &pFid); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvTree2FindFile_SMB_V2( pCtxSmb2, pTree, pFid, LwIsSetFlag( pSmbRequest->pHeader->ulFlags, SMB2_FLAGS_RELATED_OPERATION), &pFile); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvBuildFlushState_SMB_V2( pFid, pFile, &pFlushState); BAIL_ON_NT_STATUS(ntStatus); pCtxSmb2->hState = pFlushState; InterlockedIncrement(&pFlushState->refCount); pCtxSmb2->pfnStateRelease = &SrvReleaseFlushStateHandle_SMB_V2; } LWIO_LOCK_MUTEX(bInLock, &pFlushState->mutex); switch (pFlushState->stage) { case SRV_FLUSH_STAGE_SMB_V2_INITIAL: pFlushState->stage = SRV_FLUSH_STAGE_SMB_V2_FLUSH_COMPLETED; SrvPrepareFlushStateAsync_SMB_V2(pFlushState, pExecContext); ntStatus = IoFlushBuffersFile( pFlushState->pFile->hFile, pFlushState->pAcb, &pFlushState->ioStatusBlock); BAIL_ON_NT_STATUS(ntStatus); SrvReleaseFlushStateAsync_SMB_V2(pFlushState); // completed synchronously // intentional fall through case SRV_FLUSH_STAGE_SMB_V2_FLUSH_COMPLETED: ntStatus = pFlushState->ioStatusBlock.Status; BAIL_ON_NT_STATUS(ntStatus); pFlushState->stage = SRV_FLUSH_STAGE_SMB_V2_BUILD_RESPONSE; // intentional fall through case SRV_FLUSH_STAGE_SMB_V2_BUILD_RESPONSE: ntStatus = SrvBuildFlushResponse_SMB_V2(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pFlushState->stage = SRV_FLUSH_STAGE_SMB_V2_DONE; // intentional fall through case SRV_FLUSH_STAGE_SMB_V2_DONE: break; } cleanup: if (pFile) { SrvFile2Release(pFile); } if (pTree) { SrvTree2Release(pTree); } if (pSession) { SrvSession2Release(pSession); } if (pFlushState) { LWIO_UNLOCK_MUTEX(bInLock, &pFlushState->mutex); SrvReleaseFlushState_SMB_V2(pFlushState); } 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 (pFlushState) { SrvReleaseFlushStateAsync_SMB_V2(pFlushState); } break; } goto cleanup; }
static VOID RdrNegotiateGssContextWorkItem( PVOID pParam ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContext = pParam; PRDR_SESSION pSession = pContext->State.TreeConnect.pSession; PRDR_SOCKET pSocket = pSession->pSocket; PSMB_PACKET pPacket = pContext->State.TreeConnect.pPacket; PWSTR pwszNativeOS = NULL; PWSTR pwszNativeLanman = NULL; PWSTR pwszNativeDomain = NULL; PBYTE pInBlob = NULL; DWORD dwInBlobLength = 0; PBYTE pOutBlob = NULL; DWORD dwOutBlobLength = 0; PSESSION_SETUP_RESPONSE_HEADER_WC_4 pResponseHeader = NULL; BOOLEAN bSessionLocked = FALSE; if (pPacket) { status = UnmarshallSessionSetupResponse_WC_4( pPacket->pParams, pPacket->bufferLen - pPacket->bufferUsed, 0, &pResponseHeader, &pInBlob, &pwszNativeOS, &pwszNativeLanman, &pwszNativeDomain); BAIL_ON_NT_STATUS(status); dwInBlobLength = pResponseHeader->securityBlobLength; } else { pInBlob = pSession->pSocket->pSecurityBlob; dwInBlobLength = pSession->pSocket->securityBlobLen; } if (pContext->State.TreeConnect.pszCachePath) { status = SMBKrb5SetDefaultCachePath( pContext->State.TreeConnect.pszCachePath, NULL); BAIL_ON_NT_STATUS(status); } if (!pContext->State.TreeConnect.hGssContext) { status = SMBGSSContextBuild( pSocket->pwszCanonicalName, pContext->State.TreeConnect.pCreds, &pContext->State.TreeConnect.hGssContext); BAIL_ON_NT_STATUS(status); } status = SMBGSSContextNegotiate( pContext->State.TreeConnect.hGssContext, pInBlob, dwInBlobLength, &pOutBlob, &dwOutBlobLength); BAIL_ON_NT_STATUS(status); if (!SMBGSSContextNegotiateComplete(pContext->State.TreeConnect.hGssContext)) { pContext->Continue = RdrProcessSessionSetupResponse; status = RdrTransceiveSessionSetup( pContext, pSession, pOutBlob, dwOutBlobLength); BAIL_ON_NT_STATUS(status); } else { LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); if (pContext->Packet.haveSignature && (!memcmp(pPacket->pSMBHeader->extra.securitySignature, pContext->Packet.pSMBHeader->extra.securitySignature, sizeof(pContext->Packet.pSMBHeader->extra.securitySignature)))) { LWIO_LOG_WARNING("Server is exhibiting signing bug; ignoring signatures from server"); RdrSocketSetIgnoreServerSignatures(pSocket, TRUE); } status = SMBGSSContextGetSessionKey( pContext->State.TreeConnect.hGssContext, &pSession->pSessionKey, &pSession->dwSessionKeyLength); BAIL_ON_NT_STATUS(status); if (!pSocket->pSessionKey && pSession->pSessionKey && !(pContext->State.TreeConnect.pCreds->type == IO_CREDS_TYPE_PLAIN && pContext->State.TreeConnect.pCreds->payload.plain.pwszUsername[0] == '\0')) { status = LwIoAllocateMemory( pSession->dwSessionKeyLength, OUT_PPVOID(&pSocket->pSessionKey)); BAIL_ON_NT_STATUS(status); memcpy(pSocket->pSessionKey, pSession->pSessionKey, pSession->dwSessionKeyLength); pSocket->dwSessionKeyLength = pSession->dwSessionKeyLength; RdrSocketBeginSequence(pSocket); } status = RdrSocketAddSessionByUID(pSocket, pSession); BAIL_ON_NT_STATUS(status); pSession->state = RDR_SESSION_STATE_READY; RdrNotifyContextList( &pSession->StateWaiters, bSessionLocked, &pSession->mutex, status, pSession); LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RTL_FREE(&pOutBlob); if (status != STATUS_PENDING) { if (pContext->State.TreeConnect.hGssContext) { SMBGSSContextFree(pContext->State.TreeConnect.hGssContext); } RdrSessionInvalidate(pSession, status); RdrSessionRelease(pSession); RdrSessionSetupComplete(pContext, status, NULL); } return; error: goto cleanup; }
static BOOLEAN RdrProcessNegotiateResponse( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SOCKET pSocket = pContext->State.TreeConnect.pSocket; PSMB_PACKET pPacket = pParam; BOOLEAN bSocketLocked = FALSE; BOOLEAN bFreeContext = FALSE; PBYTE pGUID = NULL; PBYTE pSecurityBlob = NULL; DWORD securityBlobLen = 0; NEGOTIATE_RESPONSE_HEADER* pHeader = NULL; BAIL_ON_NT_STATUS(status); /* As a special case, it is possible to receive an SMB2 negotiate response * from an SMB1 negotiate request. */ if (pPacket->protocolVer == SMB_PROTOCOL_VERSION_2) { /* Short-circuit to SMB2 code path in connect2.c */ return RdrProcessNegotiateResponse2(pContext, status, pParam); } LWIO_LOCK_MUTEX(bSocketLocked, &pSocket->mutex); status = pPacket->pSMBHeader->error; BAIL_ON_NT_STATUS(status); status = UnmarshallNegotiateResponse( pPacket->pParams, pPacket->bufferUsed - (pPacket->pParams - pPacket->pRawBuffer), &pHeader, &pGUID, &pSecurityBlob, &securityBlobLen); BAIL_ON_NT_STATUS(status); // byte order conversions SMB_LTOH16_INPLACE(pHeader->dialectIndex); SMB_LTOH8_INPLACE(pHeader->securityMode); SMB_LTOH16_INPLACE(pHeader->maxMpxCount); SMB_LTOH16_INPLACE(pHeader->maxNumberVcs); SMB_LTOH32_INPLACE(pHeader->maxBufferSize); SMB_LTOH32_INPLACE(pHeader->maxRawSize); SMB_LTOH32_INPLACE(pHeader->sessionKey); SMB_LTOH32_INPLACE(pHeader->capabilities); SMB_LTOH32_INPLACE(pHeader->systemTimeLow); SMB_LTOH32_INPLACE(pHeader->systemTimeHigh); SMB_LTOH16_INPLACE(pHeader->serverTimeZone); SMB_LTOH8_INPLACE(pHeader->encryptionKeyLength); SMB_LTOH16_INPLACE(pHeader->byteCount); pSocket->ulMaxTransactSize = pHeader->maxBufferSize; pSocket->maxRawSize = pHeader->maxRawSize; pSocket->sessionKey = pHeader->sessionKey; pSocket->capabilities = pHeader->capabilities; pSocket->ucSecurityMode = pHeader->securityMode; pSocket->usMaxSlots = pHeader->maxMpxCount; pSocket->securityBlobLen = securityBlobLen; status = LwIoAllocateMemory( pSocket->securityBlobLen, (PVOID *) &pSocket->pSecurityBlob); BAIL_ON_NT_STATUS(status); memcpy(pSocket->pSecurityBlob, pSecurityBlob, pSocket->securityBlobLen); status = RdrSocketSetProtocol(pSocket, SMB_PROTOCOL_VERSION_1); BAIL_ON_NT_STATUS(status); pSocket->state = RDR_SOCKET_STATE_READY; RdrNotifyContextList( &pSocket->StateWaiters, bSocketLocked, &pSocket->mutex, STATUS_SUCCESS, pSocket); LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrNegotiateComplete(pContext, STATUS_SUCCESS, pSocket); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); cleanup: LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } RdrFreePacket(pPacket); return FALSE; error: if (status != STATUS_PENDING) { LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrSocketInvalidate(pSocket, status); RdrSocketRelease(pSocket); } goto cleanup; }
static VOID PvfsNotifyFullReportIrp( PPVFS_FCB pFcb, PPVFS_FCB pReportParentFcb, PPVFS_NOTIFY_REPORT_RECORD pReport ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PLW_LIST_LINKS pFilterLink = NULL; PLW_LIST_LINKS pNextLink = NULL; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; BOOLEAN bActive = FALSE; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); pFilterLink = PvfsListTraverse(pFcb->pNotifyListIrp, NULL); while(pFilterLink) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); pNextLink = PvfsListTraverse(pFcb->pNotifyListIrp, pFilterLink); /* Continue if we don't match the filter and depth */ if (!((pFilter->NotifyFilter & pReport->Filter) && ((pFcb == pReportParentFcb) || pFilter->bWatchTree))) { pFilter = NULL; pFilterLink = pNextLink; continue; } PvfsListRemoveItem(pFcb->pNotifyListIrp, pFilterLink); LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); pFilterLink = NULL; PvfsQueueCancelIrpIfRequested(pFilter->pIrpContext); bActive = PvfsIrpContextMarkIfNotSetFlag( pFilter->pIrpContext, PVFS_IRP_CTX_FLAG_CANCELLED, PVFS_IRP_CTX_FLAG_ACTIVE); if (!bActive) { PvfsFreeNotifyRecord(&pFilter); pFilterLink = pNextLink; continue; } ntError = PvfsNotifyReportIrp( pFilter->pIrpContext, pReport->Action, pReport->pszFilename); BAIL_ON_NT_STATUS(ntError); /* If we have been asked to buffer changes, move the Fitler Record to the buffer list */ if (pFilter->Buffer.Length > 0) { LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); ntError = PvfsListAddTail(pFcb->pNotifyListBuffer, pFilterLink); LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); BAIL_ON_NT_STATUS(ntError); pFilter = NULL; } /* We only process on matching IRP */ break; } cleanup: LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); if (pFilter) { PvfsFreeNotifyRecord(&pFilter); } return; error: goto cleanup; }
NTSTATUS SrvProcessGetInfo_SMB_V2( PSRV_EXEC_CONTEXT pExecContext ) { NTSTATUS ntStatus = STATUS_SUCCESS; PLWIO_SRV_CONNECTION pConnection = pExecContext->pConnection; PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext; PSRV_EXEC_CONTEXT_SMB_V2 pCtxSmb2 = pCtxProtocol->pSmb2Context; PSRV_GET_INFO_STATE_SMB_V2 pGetInfoState = NULL; PLWIO_SRV_SESSION_2 pSession = NULL; PLWIO_SRV_TREE_2 pTree = NULL; PLWIO_SRV_FILE_2 pFile = NULL; BOOLEAN bInLock = FALSE; pGetInfoState = (PSRV_GET_INFO_STATE_SMB_V2)pCtxSmb2->hState; if (pGetInfoState) { InterlockedIncrement(&pGetInfoState->refCount); } else { ULONG iMsg = pCtxSmb2->iMsg; PSRV_MESSAGE_SMB_V2 pSmbRequest = &pCtxSmb2->pRequests[iMsg]; PSMB2_GET_INFO_REQUEST_HEADER pRequestHeader = NULL; // Do not free PBYTE pInputBuffer = NULL; ULONG ulInputBufferLength = 0; ntStatus = SrvConnection2FindSession_SMB_V2( pCtxSmb2, pConnection, pSmbRequest->pHeader->ullSessionId, &pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSetStatSession2Info(pExecContext, pSession); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvSession2FindTree_SMB_V2( pCtxSmb2, pSession, pSmbRequest->pHeader->ulTid, &pTree); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SMB2UnmarshalGetInfoRequest( pSmbRequest, &pRequestHeader, &pInputBuffer, &ulInputBufferLength); BAIL_ON_NT_STATUS(ntStatus); SRV_LOG_DEBUG( pExecContext->pLogContext, SMB_PROTOCOL_VERSION_2, pSmbRequest->pHeader->command, "Get Info request params: " "command(%u),uid(%llu),cmd-seq(%llu),pid(%u),tid(%u)," "credits(%u),flags(0x%x),chain-offset(%u)," "file-id(persistent:0x%x,volatile:0x%x)," "info-class(0x%x),info-type(0x%x),flags(0x%x)," "input-buffer-length(%u),input-buffer-offset(%u)," "output-buffer-length(%u),additional-info(%u)", pSmbRequest->pHeader->command, (long long)pSmbRequest->pHeader->ullSessionId, (long long)pSmbRequest->pHeader->ullCommandSequence, pSmbRequest->pHeader->ulPid, pSmbRequest->pHeader->ulTid, pSmbRequest->pHeader->usCredits, pSmbRequest->pHeader->ulFlags, pSmbRequest->pHeader->ulChainOffset, (long long)pRequestHeader->fid.ullPersistentId, (long long)pRequestHeader->fid.ullVolatileId, pRequestHeader->ucInfoClass, pRequestHeader->ucInfoType, pRequestHeader->ulFlags, pRequestHeader->ulInputBufferLen, pRequestHeader->usInputBufferOffset, pRequestHeader->ulOutputBufferLen, pRequestHeader->ulAdditionalInfo); ntStatus = SrvTree2FindFile_SMB_V2( pCtxSmb2, pTree, &pRequestHeader->fid, &pFile); BAIL_ON_NT_STATUS(ntStatus); ntStatus = SrvBuildGetInfoState_SMB_V2( pRequestHeader, pFile, pInputBuffer, ulInputBufferLength, &pGetInfoState); BAIL_ON_NT_STATUS(ntStatus); pCtxSmb2->hState = pGetInfoState; InterlockedIncrement(&pGetInfoState->refCount); pCtxSmb2->pfnStateRelease = &SrvReleaseGetInfoStateHandle_SMB_V2; } LWIO_LOCK_MUTEX(bInLock, &pGetInfoState->mutex); switch (pGetInfoState->stage) { case SRV_GET_INFO_STAGE_SMB_V2_INITIAL: pGetInfoState->stage = SRV_GET_INFO_STAGE_SMB_V2_ATTEMPT_IO; // Intentional fall through case SRV_GET_INFO_STAGE_SMB_V2_ATTEMPT_IO: ntStatus = SrvQueryInfo_SMB_V2(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pGetInfoState->stage = SRV_GET_INFO_STAGE_SMB_V2_BUILD_RESPONSE; // Intentional fall through case SRV_GET_INFO_STAGE_SMB_V2_BUILD_RESPONSE: ntStatus = SrvBuildGetInfoResponse_SMB_V2(pExecContext); BAIL_ON_NT_STATUS(ntStatus); pGetInfoState->stage = SRV_GET_INFO_STAGE_SMB_V2_DONE; // Intentional fall through case SRV_GET_INFO_STAGE_SMB_V2_DONE: break; } cleanup: if (pFile) { SrvFile2Release(pFile); } if (pTree) { SrvTree2Release(pTree); } if (pSession) { SrvSession2Release(pSession); } if (pGetInfoState) { LWIO_UNLOCK_MUTEX(bInLock, &pGetInfoState->mutex); SrvReleaseGetInfoState_SMB_V2(pGetInfoState); } 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 (pGetInfoState) { SrvReleaseGetInfoStateAsync_SMB_V2(pGetInfoState); } break; } goto cleanup; }
static NTSTATUS PvfsNotifyReportBufferedChanges( PPVFS_CCB pCcb, PPVFS_FCB pFcb, PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; FILE_NOTIFY_CHANGE Filter = pIrpContext->pIrp->Args.ReadDirectoryChange.NotifyFilter; PVOID pBuffer = pIrpContext->pIrp->Args.ReadDirectoryChange.Buffer; ULONG Length = pIrpContext->pIrp->Args.ReadDirectoryChange.Length; PLW_LIST_LINKS pFilterLink = NULL; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); /* See if we have any changes to report immediately */ for (pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, NULL); pFilterLink; pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, pFilterLink)) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); /* To return the buffered changes, we have to match the handle and the filter */ if ((pFilter->NotifyFilter != Filter) || (pFilter->pCcb != pCcb)) { continue; } /* We have a match to check to see if we have anything */ if ((pFilter->Buffer.Length == 0) || (pFilter->Buffer.Offset == 0)) { ntError = STATUS_NOT_FOUND; BAIL_ON_NT_STATUS(ntError); } /* We have changes....Do we have enough space? Have we already overflowed the buffer? */ ntError = pFilter->Buffer.Status; BAIL_ON_NT_STATUS(ntError); if (pFilter->Buffer.Offset > Length) { PvfsNotifyClearBufferedChanges(&pFilter->Buffer); ntError = STATUS_NOTIFY_ENUM_DIR; BAIL_ON_NT_STATUS(ntError); } memcpy(pBuffer, pFilter->Buffer.pData, pFilter->Buffer.Offset); pIrpContext->pIrp->IoStatusBlock.BytesTransferred = pFilter->Buffer.Offset; PvfsNotifyClearBufferedChanges(&pFilter->Buffer); } if (pFilterLink == NULL) { ntError = STATUS_NOT_FOUND; BAIL_ON_NT_STATUS(ntError); } cleanup: LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); return ntError; error: goto cleanup; }
NTSTATUS RdrTreeConnect( PCWSTR pwszHostname, PCWSTR pwszSharename, PIO_CREDS pCreds, uid_t Uid, BOOLEAN bStopOnDfs, PRDR_OP_CONTEXT pContinue ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContext = NULL; BOOLEAN bSocketLocked = FALSE; PRDR_SOCKET pSocket = NULL; status = RdrCreateContext(pContinue->pIrp, &pContext); BAIL_ON_NT_STATUS(status); LWIO_LOG_DEBUG("Tree connect context %p will continue %p\n", pContext, pContinue); pContext->State.TreeConnect.Uid = Uid; pContext->State.TreeConnect.bStopOnDfs = bStopOnDfs; pContext->State.TreeConnect.pContinue = pContinue; status = LwRtlWC16StringDuplicate( &pContext->State.TreeConnect.pwszSharename, pwszSharename); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pCreds = pCreds; status = RdrSocketFindOrCreate( pwszHostname, &pSocket); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pSocket = pSocket; LWIO_LOCK_MUTEX(bSocketLocked, &pSocket->mutex); switch (pSocket->state) { case RDR_SOCKET_STATE_NOT_READY: pSocket->state = RDR_SOCKET_STATE_CONNECTING; LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); /* Add extra reference to socket for work item */ RdrSocketRetain(pSocket); status = LwRtlQueueWorkItem( gRdrRuntime.pThreadPool, RdrSocketConnectWorkItem, pSocket, 0); if (status) { /* Nevermind */ RdrSocketRelease(pSocket); } BAIL_ON_NT_STATUS(status); pContext->Continue = RdrProcessNegotiateResponse; status = RdrTransceiveNegotiate(pContext, pSocket); BAIL_ON_NT_STATUS(status); break; case RDR_SOCKET_STATE_CONNECTING: case RDR_SOCKET_STATE_NEGOTIATING: pContext->Continue = RdrNegotiateComplete; LwListInsertTail(&pSocket->StateWaiters, &pContext->Link); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SOCKET_STATE_READY: LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrNegotiateComplete(pContext, STATUS_SUCCESS, pSocket); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SOCKET_STATE_ERROR: status = pSocket->error; BAIL_ON_NT_STATUS(status); break; } cleanup: LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); if (status != STATUS_PENDING) { RdrFreeTreeConnectContext(pContext); } return status; error: if (status != STATUS_PENDING && pSocket) { LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrSocketInvalidate(pSocket, status); RdrSocketRelease(pSocket); } goto cleanup; }
static NTSTATUS PvfsQueryFileIdFullDirInfo( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PIRP pIrp = pIrpContext->pIrp; PPVFS_CCB pCcb = NULL; PFILE_ID_FULL_DIR_INFORMATION pFileInfo = NULL; PFILE_ID_FULL_DIR_INFORMATION pPrevFileInfo = NULL; IRP_ARGS_QUERY_DIRECTORY Args = pIrpContext->pIrp->Args.QueryDirectory; PVOID pBuffer = NULL; DWORD dwBufLen = 0; DWORD dwOffset = 0; DWORD dwConsumed = 0; BOOLEAN bLocked = FALSE; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); if (!PVFS_IS_DIR(pCcb)) { ntError = STATUS_NOT_A_DIRECTORY; BAIL_ON_NT_STATUS(ntError); } ntError = PvfsAccessCheckFileHandle(pCcb, FILE_LIST_DIRECTORY); BAIL_ON_NT_STATUS(ntError); BAIL_ON_INVALID_PTR(Args.FileInformation, ntError); if (Args.Length < sizeof(*pFileInfo)) { ntError = STATUS_BUFFER_TOO_SMALL; BAIL_ON_NT_STATUS(ntError); } pFileInfo = (PFILE_ID_FULL_DIR_INFORMATION)Args.FileInformation; /* Scen the first time through */ ntError = STATUS_SUCCESS; /* Critical region to prevent inteleaving directory enumeration */ LWIO_LOCK_MUTEX(bLocked, &pCcb->FileMutex); if (!pCcb->pDirContext->bScanned) { ntError = PvfsEnumerateDirectory( pCcb, pIrp->Args.QueryDirectory.FileSpec, -1, FALSE); } LWIO_UNLOCK_MUTEX(bLocked, &pCcb->FileMutex); BAIL_ON_NT_STATUS(ntError); /* Check for ending condition */ if (pCcb->pDirContext->dwIndex == pCcb->pDirContext->dwNumEntries) { ntError = STATUS_NO_MORE_MATCHES; BAIL_ON_NT_STATUS(ntError); } /* Fill in the buffer */ pBuffer = Args.FileInformation; dwBufLen = Args.Length; dwOffset = 0; pFileInfo = NULL; pPrevFileInfo = NULL; do { PPVFS_DIRECTORY_ENTRY pEntry = NULL; DWORD dwIndex; pFileInfo = (PFILE_ID_FULL_DIR_INFORMATION)(pBuffer + dwOffset); pFileInfo->NextEntryOffset = 0; dwIndex = pCcb->pDirContext->dwIndex; pEntry = &pCcb->pDirContext->pDirEntries[dwIndex]; ntError = FillFileIdFullDirInfoBuffer( pFileInfo, dwBufLen - dwOffset, pCcb->pszFilename, pEntry, &dwConsumed); /* If we ran out of buffer space, reset pointer to previous entry and break out of loop */ if (ntError == STATUS_BUFFER_TOO_SMALL) { pFileInfo = pPrevFileInfo; break; } /* OBJECT_NAME_NOT_FOUND - This deals with a possible race where the directory contents was read but the file was removed before we could stat() it. INSUFFICIENT_RESOURCES - Invalid UTF-8 name. ACCESS_DENIED - Special cases like $HOME/.gvfs that can't be read by root. Possibly just an Ubuntu bug but don't fail on it. https://bugs.launchpad.net/ubuntu/+source/gvfs/+bug/227724 Just skip the file and move on. */ if (ntError == STATUS_OBJECT_NAME_NOT_FOUND || ntError == STATUS_INSUFFICIENT_RESOURCES || ntError == STATUS_ACCESS_DENIED) { pFileInfo = pPrevFileInfo; pCcb->pDirContext->dwIndex++; continue; } /* Catch any other errors and bail */ BAIL_ON_NT_STATUS(ntError); pFileInfo->NextEntryOffset = dwConsumed; dwOffset += dwConsumed; pCcb->pDirContext->dwIndex++; pPrevFileInfo = pFileInfo; if (Args.ReturnSingleEntry) { break; } } /* Exit loop when we are out of buffer or out of entries. The filling function can also break us out of the loop. */ while (((dwBufLen - dwOffset) > sizeof(FILE_ID_FULL_DIR_INFORMATION)) && (pCcb->pDirContext->dwIndex < pCcb->pDirContext->dwNumEntries)); /* Update final offset */ if (pFileInfo) { pFileInfo->NextEntryOffset = 0; } pIrp->IoStatusBlock.BytesTransferred = dwOffset; ntError = STATUS_SUCCESS; cleanup: if (pCcb) { PvfsReleaseCCB(pCcb); } return ntError; error: goto cleanup; }
static VOID PvfsNotifyCleanIrpList( PVOID pContext ) { PPVFS_IRP_CONTEXT pIrpCtx = (PPVFS_IRP_CONTEXT)pContext; PPVFS_FCB pFcb = NULL; BOOLEAN bFcbLocked = FALSE; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; PLW_LIST_LINKS pFilterLink = NULL; PLW_LIST_LINKS pNextLink = NULL; BOOLEAN bFound = FALSE; LWIO_ASSERT(pIrpCtx->pScb->pOwnerFcb); // We have the IrpCtx->Scb's reference so no need to take another pFcb = pIrpCtx->pScb->pOwnerFcb; LWIO_LOCK_MUTEX(bFcbLocked, &pFcb->BaseControlBlock.Mutex); pFilterLink = PvfsListTraverse(pFcb->pNotifyListIrp, NULL); while (pFilterLink) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); pNextLink = PvfsListTraverse(pFcb->pNotifyListIrp, pFilterLink); if (pFilter->pIrpContext != pIrpCtx) { pFilterLink = pNextLink; continue; } bFound = TRUE; PvfsListRemoveItem(pFcb->pNotifyListIrp, pFilterLink); pFilterLink = NULL; LWIO_UNLOCK_MUTEX(bFcbLocked, &pFcb->BaseControlBlock.Mutex); pFilter->pIrpContext->pIrp->IoStatusBlock.Status = STATUS_CANCELLED; PvfsCompleteIrpContext(pFilter->pIrpContext); PvfsFreeNotifyRecord(&pFilter); /* Can only be one IrpContext match so we are done */ } LWIO_UNLOCK_MUTEX(bFcbLocked, &pFcb->BaseControlBlock.Mutex); if (!bFound) { pIrpCtx->pIrp->IoStatusBlock.Status = STATUS_CANCELLED; PvfsCompleteIrpContext(pIrpCtx); } if (pIrpCtx) { PvfsReleaseIrpContext(&pIrpCtx); } return; }
static BOOLEAN RdrNegotiateComplete( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SOCKET pSocket = pParam; PRDR_SESSION pSession = NULL; BOOLEAN bSessionLocked = FALSE; BOOLEAN bFreeContext = FALSE; PIO_CREDS pCreds = pContext->State.TreeConnect.pCreds; BAIL_ON_NT_STATUS(status); /* Several op contexts could be queued with this function * as the continue routine before we transition to SMB2 mode, * so we need to hand off to the correct function in this case. * Subsequent attempts should go straight to connect2.c */ if (pSocket->version == SMB_PROTOCOL_VERSION_2) { /* Short circuit to SMB2 session setup logic in connect2.c */ return RdrNegotiateComplete2(pContext, status, pParam); } if (pContext->State.TreeConnect.bStopOnDfs && pSocket->capabilities & CAP_DFS) { /* Abort tree connect because we need to do DFS referral processing first */ status = STATUS_DFS_EXIT_PATH_FOUND; BAIL_ON_NT_STATUS(status); } status = RdrSessionFindOrCreate( &pSocket, pContext->State.TreeConnect.pCreds, pContext->State.TreeConnect.Uid, &pSession); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pSession = pSession; LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); switch (pSession->state) { case RDR_SESSION_STATE_NOT_READY: pSession->state = RDR_SESSION_STATE_INITIALIZING; switch (pCreds->type) { case IO_CREDS_TYPE_KRB5_TGT: status = SMBCredTokenToKrb5CredCache( pCreds, &pContext->State.TreeConnect.pszCachePath); BAIL_ON_NT_STATUS(status); break; case IO_CREDS_TYPE_PLAIN: break; default: status = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(status); } LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrProcessSessionSetupResponse(pContext, STATUS_SUCCESS, NULL); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_INITIALIZING: pContext->Continue = RdrSessionSetupComplete; LwListInsertTail(&pSession->StateWaiters, &pContext->Link); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_READY: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_ERROR: status = pSession->error; BAIL_ON_NT_STATUS(status); break; } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } return FALSE; error: if (status != STATUS_PENDING && pSession) { LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSessionInvalidate(pSession, status); } RdrSessionRelease(pSession); } if (status != STATUS_PENDING && pSocket) { if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSocketInvalidate(pSocket, status); } RdrSocketRelease(pSocket); } goto cleanup; }