//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1995.
//
//  File:       certmap.c
//
//  Contents:   Routines to call appropriate mapper, be it the system
//              default one (in the LSA process) or an application one (in
//              the application process).
//
//  Classes:
//
//  Functions:
//
//  History:    12-23-96   jbanes   Created.
//
//----------------------------------------------------------------------------

#include <spbase.h>

DWORD
WINAPI
SslReferenceMapper(HMAPPER *phMapper)
{
    DWORD dwResult;
    SecBuffer Input;
    SecBuffer Output;
    SECURITY_STATUS scRet;

    if(phMapper == NULL)
    {
        return SP_LOG_RESULT(-1);
    }

    if(phMapper->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)
    {
        // System mapper.
        return phMapper->m_vtable->ReferenceMapper(phMapper);
    }
    else
    {
        // Application mapper.

        Input.BufferType = SECBUFFER_DATA;
        Input.cbBuffer   = 0;
        Input.pvBuffer   = NULL;

        scRet = PerformApplicationCallback( SCH_REFERENCE_MAPPER_CALLBACK,
                                            (ULONG_PTR)phMapper->m_Reserved1,
                                            TRUE,
                                            &Input,
                                            &Output,
                                            TRUE);
        if(!NT_SUCCESS(scRet))
        {
            DebugLog((DEB_ERROR, "Error 0x%x referencing mapper\n", scRet));
            return SP_LOG_RESULT(scRet);
        }

        SP_ASSERT(Output.cbBuffer == sizeof(DWORD));

        dwResult = *(PDWORD)(Output.pvBuffer);

        SPExternalFree(Output.pvBuffer);

        return dwResult;
    }
}

DWORD
WINAPI
SslDereferenceMapper(HMAPPER *phMapper)
{
    DWORD dwResult;
    SecBuffer Input;
    SecBuffer Output;
    SECURITY_STATUS scRet;

    if(phMapper == NULL)
    {
        return SP_LOG_RESULT(0);
    }

    if(phMapper->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)
    {
        // System mapper.
        return phMapper->m_vtable->DeReferenceMapper(phMapper);
    }
    else
    {
        // Application mapper.

        Input.BufferType = SECBUFFER_DATA;
        Input.cbBuffer   = 0;
        Input.pvBuffer   = NULL;

        scRet = PerformApplicationCallback( SCH_REFERENCE_MAPPER_CALLBACK,
                                            (ULONG_PTR)phMapper->m_Reserved1,
                                            FALSE,
                                            &Input,
                                            &Output,
                                            TRUE);
        if(!NT_SUCCESS(scRet))
        {
            DebugLog((DEB_ERROR, "Error 0x%x dereferencing mapper\n", scRet));
            return SP_LOG_RESULT(scRet);
        }

        SP_ASSERT(Output.cbBuffer == sizeof(DWORD));

        dwResult = *(PDWORD)(Output.pvBuffer);

        SPExternalFree(Output.pvBuffer);

        return dwResult;
    }
}

//+---------------------------------------------------------------------------
//
//  Function:   ReferenceMapperCallback
//
//  Synopsis:   Reference (or dereference) the application mapper.
//
//  Arguments:  [fReference]    --  Whether to reference or dereference.
//              [dwArg2]        --  Not used.
//              [pInput]        --  HMAPPER structure.
//              [pOutput]       --  DWORD reference count.
//
//  History:    10-17-97   jbanes   Created
//
//  Notes:
//
//----------------------------------------------------------------------------
SECURITY_STATUS
ReferenceMapperCallback(
    ULONG_PTR Mapper,
    ULONG_PTR fReference,
    SecBuffer *pInput,
    SecBuffer *pOutput)
{
    DWORD dwResult;
    HMAPPER *phMapper;

    if(!SchannelInit(TRUE))
    {
        return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
    }

    DebugLog((DEB_TRACE, "ReferenceMapperCallback\n"));

    phMapper = (HMAPPER *)Mapper;

    // Perform reference counting.
    try
    {
        if(fReference)
        {
            dwResult = phMapper->m_vtable->ReferenceMapper(phMapper);
        }
        else
        {
            dwResult = phMapper->m_vtable->DeReferenceMapper(phMapper);
        }
    }
    except(EXCEPTION_EXECUTE_HANDLER)
    {
        return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
    }

    // Build output buffer
    pOutput->BufferType = SECBUFFER_DATA;
    pOutput->cbBuffer   = sizeof(DWORD);
    pOutput->pvBuffer   = PvExtVirtualAlloc(pOutput->cbBuffer);
    if(pOutput->pvBuffer == NULL)
    {
        return SEC_E_INSUFFICIENT_MEMORY;
    }

    *(DWORD *)(pOutput->pvBuffer) = dwResult;

    return SEC_E_OK;
}


SECURITY_STATUS
WINAPI
SslGetMapperIssuerList(
    HMAPPER *   phMapper,           // in
    BYTE **     ppIssuerList,       // out
    DWORD *     pcbIssuerList)      // out
{
    SecBuffer Input;
    SecBuffer Output;
    SECURITY_STATUS Status;

    if(phMapper == NULL)
    {
        return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
    }

    if(phMapper->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)
    {
        // System mapper.

        Status = phMapper->m_vtable->GetIssuerList(phMapper,
                                              0,
                                              NULL,
                                              pcbIssuerList);

        if(!NT_SUCCESS(Status))
        {
            return SP_LOG_RESULT(Status);
        }

        *ppIssuerList = SPExternalAlloc(*pcbIssuerList);
        if(*ppIssuerList == NULL)
        {
            return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
        }

        Status = phMapper->m_vtable->GetIssuerList(phMapper,
                                              0,
                                              *ppIssuerList,
                                              pcbIssuerList);
        if(!NT_SUCCESS(Status))
        {
            SPExternalFree(*ppIssuerList);
            return SP_LOG_RESULT(Status);
        }

        return Status;
    }
    else
    {
        // Application mapper.

        Input.BufferType = SECBUFFER_DATA;
        Input.cbBuffer   = 0;
        Input.pvBuffer   = NULL;

        Status = PerformApplicationCallback( SCH_GET_MAPPER_ISSUER_LIST_CALLBACK,
                                            (ULONG_PTR)phMapper->m_Reserved1,
                                            0,
                                            &Input,
                                            &Output,
                                            TRUE);
        if(!NT_SUCCESS(Status))
        {
            DebugLog((DEB_ERROR, "Error 0x%x getting mapper issuer list\n", Status));

            *ppIssuerList  = NULL;
            *pcbIssuerList = 0;

            return Status;
        }

        *ppIssuerList  = Output.pvBuffer;
        *pcbIssuerList = Output.cbBuffer;

        return Status;
    }
}

//+---------------------------------------------------------------------------
//
//  Function:   GetMapperIssuerListCallback
//
//  Synopsis:   Query the application mapper for the list of trusted CAs.
//
//  Arguments:  [pIssuerList]   --  Pointer to LSA buffer.
//              [cbIssuerList]  --  Size of LSA buffer.
//              [pInput]        --  HMAPPER structure.
//              [pOutput]       --  Issuer list.
//
//  History:    10-17-97   jbanes   Created
//
//  Notes:      The format of the output buffer is as follows:
//
//              BYTE        rgbIssuerList;
//
//----------------------------------------------------------------------------
SECURITY_STATUS
GetMapperIssuerListCallback(
    ULONG_PTR Mapper,
    ULONG_PTR dwArg2,
    SecBuffer *pInput,
    SecBuffer *pOutput)
{
    HMAPPER *   phMapper;
    DWORD       cbIssuerList;
    DWORD       Status;

    if(!SchannelInit(TRUE))
    {
        return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
    }

    DebugLog((DEB_TRACE, "GetMapperIssuerListCallback\n"));

    phMapper = (HMAPPER *)Mapper;

    pOutput->BufferType = SECBUFFER_DATA;
    pOutput->cbBuffer   = 0;
    pOutput->pvBuffer   = NULL;

    try
    {
        Status = phMapper->m_vtable->GetIssuerList(phMapper,
                                              NULL,
                                              NULL,
                                              &cbIssuerList);
        if(!NT_SUCCESS(Status))
        {
            SP_LOG_RESULT(Status);
            goto error;
        }

        pOutput->cbBuffer = cbIssuerList;
        pOutput->pvBuffer = PvExtVirtualAlloc(pOutput->cbBuffer);
        if(pOutput->pvBuffer == NULL)
        {
            Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
            goto error;
        }

        Status = phMapper->m_vtable->GetIssuerList(phMapper,
                                              NULL,
                                              pOutput->pvBuffer,
                                              &cbIssuerList);
        if(!NT_SUCCESS(Status))
        {
            SP_LOG_RESULT(Status);
            goto error;
        }
    }
    except(EXCEPTION_EXECUTE_HANDLER)
    {
    	Status = SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
        goto error;
    }

    return SEC_E_OK;

error:

    if(pOutput->pvBuffer)
    {
        FreeExtVirtualAlloc(pOutput->pvBuffer, pOutput->cbBuffer);
        pOutput->pvBuffer = NULL;
    }

    return Status;
}


SECURITY_STATUS
WINAPI
SslGetMapperChallenge(
    HMAPPER *   phMapper,           // in
    BYTE *      pAuthenticatorId,   // in
    DWORD       cbAuthenticatorId,  // in
    BYTE *      pChallenge,         // out
    DWORD *     pcbChallenge)       // out
{
    return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}


SECURITY_STATUS
WINAPI
SslMapCredential(
    HMAPPER *   phMapper,           // in
    DWORD       dwCredentialType,   // in
    PCCERT_CONTEXT pCredential,     // in
    PCCERT_CONTEXT pAuthority,      // in
    HLOCATOR *  phLocator)          // out
{
    SecBuffer       Input;
    SecBuffer       Output;
    PBYTE           pbBuffer;
    DWORD           cbCredential;
    DWORD           cbAuthority;
    SECURITY_STATUS scRet;

    if(phMapper == NULL)
    {
        return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
    }

    if(phMapper->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)
    {
        // System mapper.
        scRet = phMapper->m_vtable->MapCredential(phMapper,
                                                 dwCredentialType,
                                                 pCredential,
                                                 pAuthority,
                                                 phLocator);
        return MapWinTrustError(scRet, SEC_E_NO_IMPERSONATION, 0);
    }
    else
    {
        // Application mapper.

        // Determine the size of the serialized cert contexts.
        scRet = SerializeCertContext(pCredential,
                                     NULL,
                                     &cbCredential);
        if(FAILED(scRet))
        {
            return SP_LOG_RESULT(scRet);
        }
        if(pAuthority)
        {
            if(!CertSerializeCertificateStoreElement(
                            pAuthority,
                            0, NULL,
                            &cbAuthority))
            {
                return SP_LOG_RESULT(GetLastError());
            }
        }
        else
        {
            cbAuthority = 0;
        }

        // Allocate memory for the input buffer.
        Input.BufferType = SECBUFFER_DATA;
        Input.cbBuffer   = sizeof(DWORD) + cbCredential +
                           sizeof(DWORD) + cbAuthority;
        Input.pvBuffer   = LocalAlloc(LMEM_FIXED, Input.cbBuffer);
        if(Input.pvBuffer == NULL)
        {
            return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
        }

        // Build the input buffer.
        pbBuffer = Input.pvBuffer;

        *(PDWORD)pbBuffer = cbCredential;
        pbBuffer += sizeof(DWORD);

        *(PDWORD)pbBuffer = cbAuthority;
        pbBuffer += sizeof(DWORD);

        scRet = SerializeCertContext(pCredential,
                                     pbBuffer,
                                     &cbCredential);
        if(FAILED(scRet))
        {
            LocalFree(Input.pvBuffer);
            return SP_LOG_RESULT(scRet);
        }
        pbBuffer += cbCredential;

        if(pAuthority)
        {
            if(!CertSerializeCertificateStoreElement(
                            pAuthority,
                            0,
                            pbBuffer,
                            &cbAuthority))
            {
                scRet = SP_LOG_RESULT(GetLastError());
                LocalFree(Input.pvBuffer);
                return scRet;
            }
            pbBuffer += cbAuthority;
        }

        SP_ASSERT(pbBuffer - (PBYTE)Input.pvBuffer == (INT)Input.cbBuffer);


        scRet = PerformApplicationCallback( SCH_MAP_CREDENTIAL_CALLBACK,
                                            (ULONG_PTR)phMapper->m_Reserved1,
                                            dwCredentialType,
                                            &Input,
                                            &Output,
                                            TRUE);
        LocalFree(Input.pvBuffer);
        if(!NT_SUCCESS(scRet))
        {
            DebugLog((DEB_ERROR, "Error 0x%x mapping credential\n", scRet));
            return scRet;
        }

        SP_ASSERT(Output.cbBuffer == sizeof(HLOCATOR));
        CopyMemory(phLocator, Output.pvBuffer, sizeof(HLOCATOR));

        SPExternalFree(Output.pvBuffer);

        return SEC_E_OK;
    }
}

//+---------------------------------------------------------------------------
//
//  Function:   MapCredentialCallback
//
//  Synopsis:   Maps the specified certificate to an NT user account, via
//              an application-installed certificate mapper.
//
//  Arguments:  [dwCredentialType]  --  Credential type.
//              [dwArg2]            --  Not used.
//              [pInput]            --  See notes.
//              [pOutput]           --  Returned locator.
//
//  History:    12-29-97   jbanes   Created
//
//  Notes:      The format of the input buffer is:
//
//              DWORD           cbCredential;
//              DWORD           cbAuthority;
//              BYTE            rgbCredential[cbCredential];
//              BYTE            rgbAuthority[cbAuthority];
//
//              The credential and authority fields consist of serialized
//              CERT_CONTEXT structures.
//
//----------------------------------------------------------------------------
SECURITY_STATUS
MapCredentialCallback(
    ULONG_PTR Mapper,
    ULONG_PTR dwCredentialType,
    SecBuffer *pInput,
    SecBuffer *pOutput)
{
    HMAPPER *       phMapper;
    PCCERT_CONTEXT  pCredential = NULL;
    PCCERT_CONTEXT  pAuthority  = NULL;
    SECURITY_STATUS scRet;
    DWORD           cbCredential;
    DWORD           cbAuthority;
    PBYTE           pbBuffer;
    HLOCATOR        hLocator;


    if(!SchannelInit(TRUE))
    {
        return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
    }

    DebugLog((DEB_TRACE, "MapCredentialCallback\n"));

    phMapper = (HMAPPER *)Mapper;


    // Initialize output buffer.
    pOutput->BufferType = SECBUFFER_DATA;
    pOutput->cbBuffer   = 0;
    pOutput->pvBuffer   = NULL;


    //
    // Parse input buffer
    //

    pbBuffer = pInput->pvBuffer;

    if(pInput->cbBuffer < sizeof(DWORD) * 2)
    {
        scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
        goto done;
    }

    cbCredential = *(PDWORD)pbBuffer;
    pbBuffer += sizeof(DWORD);

    cbAuthority = *(PDWORD)pbBuffer;
    pbBuffer += sizeof(DWORD);

    if(pInput->cbBuffer < sizeof(DWORD) * 2 + cbCredential + cbAuthority)
    {
        scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
        goto done;
    }

    // Deserialize "credential" certificate context.
    scRet = DeserializeCertContext(&pCredential,
                                   pbBuffer,
                                   cbCredential);
    if(FAILED(scRet))
    {
        scRet = SP_LOG_RESULT(scRet);
        goto done;
    }
    pbBuffer += cbCredential;

    // Deserialize "authority" certificate context.
    if(cbAuthority && pCredential->hCertStore)
    {
        if(!CertAddSerializedElementToStore(pCredential->hCertStore,
                                            pbBuffer + sizeof(DWORD),
                                            *(DWORD *)pbBuffer,
                                            CERT_STORE_ADD_USE_EXISTING,
                                            0,
                                            CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
                                            NULL,
                                            &pAuthority))
        {
            scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
            goto done;
        }
    }


    //
    // Call application mapper.
    //

    try
    {
        scRet = phMapper->m_vtable->MapCredential(phMapper,
                                              (DWORD)dwCredentialType,
                                              pCredential,
                                              pAuthority,
                                              &hLocator);
        if(!NT_SUCCESS(scRet))
        {
            // Mapping was unsuccessful.
            scRet = MapWinTrustError(scRet, SEC_E_NO_IMPERSONATION, 0);
            goto done;
        }
    }
    except(EXCEPTION_EXECUTE_HANDLER)
    {
        return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
    }


    //
    // Build output buffer
    //

    pOutput->BufferType = SECBUFFER_DATA;
    pOutput->cbBuffer   = sizeof(HLOCATOR);
    pOutput->pvBuffer   = PvExtVirtualAlloc(pOutput->cbBuffer);
    if(pOutput->pvBuffer == NULL)
    {
        scRet = SEC_E_INSUFFICIENT_MEMORY;
        goto done;
    }

    *(HLOCATOR *)(pOutput->pvBuffer) = hLocator;

    scRet = SEC_E_OK;


done:

    if(pCredential)
    {
        CertFreeCertificateContext(pCredential);
    }
    if(pAuthority)
    {
        CertFreeCertificateContext(pAuthority);
    }

    return scRet;
}


SECURITY_STATUS
WINAPI
SslCloseLocator(
    HMAPPER *   phMapper,           // in
    HLOCATOR    hLocator)           // in
{
    SecBuffer Input;
    SecBuffer Output;
    SECURITY_STATUS scRet;

    if(phMapper == NULL)
    {
        return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
    }

    if(phMapper->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)
    {
        // System mapper.
        return phMapper->m_vtable->CloseLocator(phMapper,
                                                hLocator);
    }
    else
    {
        // Application mapper.

        Input.BufferType = SECBUFFER_DATA;
        Input.cbBuffer   = 0;
        Input.pvBuffer   = NULL;

        scRet = PerformApplicationCallback( SCH_CLOSE_LOCATOR_CALLBACK,
                                            (ULONG_PTR)phMapper->m_Reserved1,
                                            (ULONG_PTR)hLocator,
                                            &Input,
                                            &Output,
                                            FALSE);
        if(!NT_SUCCESS(scRet))
        {
            DebugLog((DEB_ERROR, "Error 0x%x closing locator\n", scRet));
            return scRet;
        }

        SP_ASSERT(Output.cbBuffer == 0);

        return scRet;
    }
}

//+---------------------------------------------------------------------------
//
//  Function:   CloseLocatorCallback
//
//  Synopsis:   Reference (or dereference) the application mapper.
//
//  Arguments:  [hLocator]  --  Handle to locator.
//              [dwArg2]    --  Not used.
//              [pInput]    --  HMAPPER structure.
//              [pOutput]   --  Not used.
//
//  History:    12-28-97   jbanes   Created
//
//  Notes:
//
//----------------------------------------------------------------------------
SECURITY_STATUS
CloseLocatorCallback(
    ULONG_PTR Mapper,
    ULONG_PTR hLocator,
    SecBuffer *pInput,
    SecBuffer *pOutput)
{
    HMAPPER *phMapper;
    SECURITY_STATUS Status;

    if(!SchannelInit(TRUE))
    {
        return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
    }

    DebugLog((DEB_TRACE, "CloseLocatorCallback\n"));

    phMapper = (HMAPPER *)Mapper;

    // Close the locator.
    try
    {
        Status = phMapper->m_vtable->CloseLocator(phMapper, hLocator);
    }
    except(EXCEPTION_EXECUTE_HANDLER)
    {
        return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
    }

    // Build output buffer
    pOutput->BufferType = SECBUFFER_DATA;
    pOutput->cbBuffer   = 0;
    pOutput->pvBuffer   = NULL;

    return Status;
}

SECURITY_STATUS
WINAPI
SslQueryMappedCredentialAttributes(
    HMAPPER *   phMapper,           // in
    HLOCATOR    hLocator,           // in
    DWORD       dwAttribute,        // in
    PVOID *     ppBuffer)           // out
{
    SecBuffer Input;
    SecBuffer Output;
    SECURITY_STATUS scRet;

    if(phMapper == NULL)
    {
        return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
    }

    if(phMapper->m_dwFlags & SCH_FLAG_SYSTEM_MAPPER)
    {
        // System mapper.
        return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
    }
    else
    {
        // Application mapper.

        Input.BufferType = SECBUFFER_DATA;
        Input.cbBuffer   = sizeof(DWORD);
        Input.pvBuffer   = &dwAttribute;

        scRet = PerformApplicationCallback( SCH_GET_MAPPER_ATTRIBUTES_CALLBACK,
                                            (ULONG_PTR)phMapper->m_Reserved1,
                                            hLocator,
                                            &Input,
                                            &Output,
                                            TRUE);
        if(!NT_SUCCESS(scRet))
        {
            DebugLog((DEB_ERROR, "Error 0x%x querying mapped attribute.\n", scRet));
            return scRet;
        }

        if(Output.cbBuffer != sizeof(PVOID))
        {
            SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
        }

        *ppBuffer = *(PVOID *)Output.pvBuffer;

        SPExternalFree(Output.pvBuffer); //this is allocated by SPExternalAlloc()

        return SEC_E_OK;
    }
}

//+---------------------------------------------------------------------------
//
//  Function:   QueryMappedCredAttributesCallback
//
//  Synopsis:   Queries the application mapper for the specified property.
//
//  Arguments:  [hLocator]      --  Handle to locator.
//              [dwAttribute]   --  Attribute to query.
//              [pInput]        --  HMAPPER structure.
//              [pOutput]       --  Pointer to attribute data (in the
//                                  application's address space).
//
//  History:    03-16-98   jbanes   Created
//
//  Notes:
//
//----------------------------------------------------------------------------
SECURITY_STATUS
QueryMappedCredAttributesCallback(
    ULONG_PTR Mapper,
    ULONG_PTR hLocator,
    SecBuffer *pInput,
    SecBuffer *pOutput)
{
    HMAPPER *   phMapper;
    DWORD       dwAttribute;
    PVOID       pvBuffer;
    DWORD       cbBuffer;
    DWORD       Status;

    if(!SchannelInit(TRUE))
    {
        return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
    }

    DebugLog((DEB_TRACE, "QueryMappedCredAttributesCallback\n"));

    phMapper = (HMAPPER *)Mapper;

    // Parse input buffer
    SP_ASSERT(pInput->cbBuffer == sizeof(DWORD));
    dwAttribute = *(DWORD *)pInput->pvBuffer;

    // Query propery.
    try
    {
        // Determine buffer size.
        Status = phMapper->m_vtable->QueryMappedCredentialAttributes(
                                    phMapper,
                                    hLocator,
                                    dwAttribute,
                                    NULL,
                                    &cbBuffer);
        if(FAILED(Status))
        {
            return SP_LOG_RESULT(Status);
        }

        // Allocate memory. This gets freed by the APPLICATION with FreeSecurityBuffer() call
        // SPExternalAlloc() for the above reason!!!!

        pvBuffer = SPExternalAlloc(cbBuffer);
        if(pvBuffer == NULL)
        {
            return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
        }

        // Read propery.
        Status = phMapper->m_vtable->QueryMappedCredentialAttributes(
                                    phMapper,
                                    hLocator,
                                    dwAttribute,
                                    pvBuffer,
                                    &cbBuffer);
        if(FAILED(Status))
        {
            SPExternalFree(pvBuffer);
            return SP_LOG_RESULT(Status);
        }
    }
    except(EXCEPTION_EXECUTE_HANDLER)
    {
        return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
    }

    // Build output buffer
    pOutput->BufferType = SECBUFFER_DATA;
    pOutput->cbBuffer   = sizeof(PVOID);
    pOutput->pvBuffer   = PvExtVirtualAlloc(pOutput->cbBuffer);
    if(pOutput->pvBuffer == NULL)
    {
        SPExternalFree(pvBuffer);
        return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
    }

    *(PVOID *)(pOutput->pvBuffer) = pvBuffer;

    return SEC_E_OK;
}