示例#1
0
static
BOOLEAN
RdrTreeConnect2Complete(
    PRDR_OP_CONTEXT pContext,
    NTSTATUS status,
    PVOID pParam
    )
{
    PRDR_TREE2 pTree = pParam;

    BAIL_ON_NT_STATUS(status);

cleanup:

    if (status != STATUS_PENDING)
    {
        RdrContinueContext(pContext->State.TreeConnect.pContinue, status, pTree);
        RdrFreeTreeConnectContext(pContext);
    }

    return FALSE;

error:

    if (status != STATUS_PENDING && pTree)
    {
        RdrTree2Release(pTree);
        pTree = NULL;
    }

    goto cleanup;
}
示例#2
0
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;
}
示例#3
0
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;
}
示例#4
0
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;
}
示例#5
0
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;
}
示例#6
0
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;
}
示例#7
0
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;
}
示例#8
0
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;
}