/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*-
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 * Editor Settings: expandtabs and use 4 spaces for indentation */

#include "includes.h"

static
VOID
SrvCCBFree(
    PSRV_CCB pCCB
    );

NTSTATUS
SrvCCBCreate(
    PSRV_IRP_CONTEXT pIrpContext,
    PSRV_CCB*        ppCCB
    )
{
    NTSTATUS ntStatus = 0;
    PSRV_CCB pCCB = NULL;
    PIO_SECURITY_CONTEXT_PROCESS_INFORMATION pProcInfo = NULL;
    PACCESS_TOKEN pToken = NULL;
    PWSTR pUser = NULL;
    PWSTR pDomain = NULL;

    pProcInfo = IoSecurityGetProcessInfo(pIrpContext->pIrp->Args.Create.SecurityContext);
    pToken = IoSecurityGetAccessToken(pIrpContext->pIrp->Args.Create.SecurityContext);

    /* Ignore failure to get NT name, which is expected for root */
    (void) SrvIoGetNtNameFromIoSecurityContext(
        pIrpContext->pIrp->Args.Create.SecurityContext,
        &pDomain,
        &pUser);

    ntStatus = SrvAllocateMemory(sizeof(SRV_CCB), (PVOID*)&pCCB);
    BAIL_ON_NT_STATUS(ntStatus);

    pCCB->CcbType = SRV_CCB_DEVICE;
    pCCB->refCount = 1;
    pCCB->UnixUid = pProcInfo ? pProcInfo->Uid : -1;
    pCCB->pToken = pToken;
    RtlReferenceAccessToken(pToken);
    pCCB->pUser = pUser;
    pUser = NULL;
    pCCB->pDomain = pDomain;
    pDomain = NULL;

    *ppCCB = pCCB;

cleanup:

    RTL_FREE(&pUser);
    RTL_FREE(&pDomain);

    return ntStatus;

error:

    *ppCCB = NULL;

    goto cleanup;
}

NTSTATUS
SrvCCBGet(
    IO_FILE_HANDLE FileHandle,
    PSRV_CCB*      ppCCB
    )
{
    NTSTATUS ntStatus = 0;
    PSRV_CCB pCCB = NULL;

    pCCB = (PSRV_CCB)IoFileGetContext(FileHandle);
    if (!pCCB)
    {
        ntStatus = STATUS_INVALID_PARAMETER;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    *ppCCB = pCCB;

cleanup:

    return ntStatus;

error:

    *ppCCB = NULL;

    goto cleanup;
}

NTSTATUS
SrvCCBSet(
    IO_FILE_HANDLE FileHandle,
    PSRV_CCB       pCCB
    )
{
    return IoFileSetContext(FileHandle, pCCB);
}

VOID
SrvCCBRelease(
    PSRV_CCB pCCB
    )
{
    if (InterlockedDecrement(&pCCB->refCount) == 0)
    {
        SrvCCBFree(pCCB);
    }
}

static
VOID
SrvCCBFree(
    PSRV_CCB pCCB
    )
{
    RTL_FREE(&pCCB->pDomain);
    RTL_FREE(&pCCB->pUser);
    RtlReleaseAccessToken(&pCCB->pToken);
    SrvFreeMemory(pCCB);
}

