//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996-1996
//
// File:        tlsrpc.c
//
// Contents:    Various RPC function to accept client request
//
// History:     12-09-98    HueiWang    Created
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#include "server.h"
#include "gencert.h"
#include "kp.h"
#include "keypack.h"
#include "clilic.h"
#include "postjob.h"
#include "srvlist.h"
#include "utils.h"
#include "misc.h"
#include "licreq.h"
#include "conlic.h"
#include "globals.h"
#include "db.h"
#include "tlscert.h"
#include "permlic.h"
#include "remotedb.h"

  

CCMutex g_AdminLock;
CCMutex g_RpcLock;
CCEvent g_ServerShutDown(TRUE, FALSE);

BOOL 
VerifyLicenseRequest(
    PTLSLICENSEREQUEST pLicenseRequest
    )
/*++

--*/
{
    BOOL bValid = FALSE;

    if(pLicenseRequest == NULL)
    {
        DBGPrintf(
                DBG_INFORMATION,
                DBG_FACILITY_RPC,
                DBGLEVEL_FUNCTION_TRACE,
                _TEXT("VerifyLicenseRequest() invalid input\n")
            );

        goto cleanup;
    }

    if( pLicenseRequest->cbEncryptedHwid == 0 || 
        pLicenseRequest->pbEncryptedHwid == NULL)
    {
        DBGPrintf(
                DBG_INFORMATION,
                DBG_FACILITY_RPC,
                DBGLEVEL_FUNCTION_TRACE,
                _TEXT("VerifyLicenseRequest() invalid HWID\n")
            );


        goto cleanup;
    }

    if( pLicenseRequest->ProductInfo.cbCompanyName == 0 || 
        pLicenseRequest->ProductInfo.pbCompanyName == NULL )
    {
        DBGPrintf(
                DBG_INFORMATION,
                DBG_FACILITY_RPC,
                DBGLEVEL_FUNCTION_TRACE,
                _TEXT("VerifyLicenseRequest() invalid company name\n")
            );


        goto cleanup;
    }

    if( pLicenseRequest->ProductInfo.cbProductID == 0 || 
        pLicenseRequest->ProductInfo.pbProductID == NULL )
    {
        DBGPrintf(
                DBG_INFORMATION,
                DBG_FACILITY_RPC,
                DBGLEVEL_FUNCTION_TRACE,
                _TEXT("VerifyLicenseRequest() invalid product id\n")
            );


        goto cleanup;
    }

    bValid = TRUE;

cleanup:

    return bValid;
}


/////////////////////////////////////////////////////////////////////////////

BOOL 
WaitForMyTurnOrShutdown(
    HANDLE hHandle, 
    DWORD dwWaitTime
    )
/*


*/
{
    // 
    // Shutdown event is first one in the wait list
    // reason is when service thread signal shutdow, at the same time,
    // there might be a RPC call entering WaitForMultipleObjects() call and
    // it will return WAIT_OBJECT_0 and continue on, this is not desirable
    // since we want it to return can't get handle and exit RPC call immediately
    //
    HANDLE  waitHandles[2]={g_ServerShutDown.hEvent, hHandle};
    DWORD   dwStatus;

    //
    // Could be return shutting down...
    //
    dwStatus=WaitForMultipleObjects(
                        sizeof(waitHandles)/sizeof(waitHandles[0]), 
                        waitHandles, 
                        FALSE, 
                        dwWaitTime
                    );

    return (dwStatus == WAIT_OBJECT_0 + 1) || (dwStatus == WAIT_ABANDONED_0 + 1);
}

//////////////////////////////////////////////////////

HANDLE
GetServiceShutdownHandle()
{
    return g_ServerShutDown.hEvent;
}

void 
ServiceSignalShutdown()
{
    g_ServerShutDown.SetEvent();
}

void 
ServiceResetShutdownEvent()
{
    g_ServerShutDown.ResetEvent();
}

BOOL
IsServiceShuttingdown()
{
    return (WaitForSingleObject(g_ServerShutDown.hEvent, 0) == WAIT_OBJECT_0);
}


//////////////////////////////////////////////////////

BOOL 
AcquireRPCExclusiveLock(
    IN DWORD dwWaitTime
    )

/*++

Abstract:

    Acquire exclusive lock for RPC interface.

Parameter:

    dwWaitTime : Wait time.

Return:

    TRUE/FALSE

--*/

{
    return WaitForMyTurnOrShutdown(
                                g_RpcLock.hMutex,
                                dwWaitTime
                            );
}

//////////////////////////////////////////////////////

void
ReleaseRPCExclusiveLock()
{
    g_RpcLock.Unlock();
}

//////////////////////////////////////////////////////

BOOL
AcquireAdministrativeLock(
    IN DWORD dwWaitTime
    )
/*++

Abstract:

    Acquire lock for administrative action.

Parameter:

    dwWaitTime : Time to wait for the lock.

Returns:

    TRUE/FALSE.

--*/

{
    return WaitForMyTurnOrShutdown(
                                g_AdminLock.hMutex, 
                                dwWaitTime
                            );
}

//////////////////////////////////////////////////////

void
ReleaseAdministrativeLock()
/*++

--*/
{
    g_AdminLock.Unlock();
}


//-----------------------------------------------------------------------

DWORD 
TLSVerifyHydraCertificate(
    PBYTE pHSCert, 
    DWORD cbHSCert
    )
/*

*/
{
    DWORD dwStatus;

    dwStatus = TLSVerifyProprietyChainedCertificate(
                                        g_hCryptProv, 
                                        pHSCert, 
                                        cbHSCert
                                    );

    if(dwStatus != ERROR_SUCCESS)
    {
        Hydra_Server_Cert hCert;

        memset(&hCert, 0, sizeof(Hydra_Server_Cert));

        dwStatus=UnpackHydraServerCertificate(pHSCert, cbHSCert, &hCert);
        if(dwStatus == LICENSE_STATUS_OK)
        {
            dwStatus=LicenseVerifyServerCert(&hCert);

            if(hCert.PublicKeyData.pBlob)
                free(hCert.PublicKeyData.pBlob);

            if(hCert.SignatureBlob.pBlob)
                free(hCert.SignatureBlob.pBlob);
        }
    }

    return dwStatus;
}

//-------------------------------------------------------------------------
// 
//  General RPC routines
//

void * __RPC_USER 
MIDL_user_allocate(size_t size)
{
    void* ptr=AllocateMemory(size);

    // DBGPrintf(0xFFFFFFFF, _TEXT("Allocate 0x%08x, size %d\n"), ptr, size);
    return ptr;
}

void __RPC_USER 
MIDL_user_free(void *pointer)
{
    FreeMemory(pointer);
}


//-------------------------------------------------------------------------

BOOL 
ValidContextHandle(
    IN PCONTEXT_HANDLE phContext
    )
/*++
Description: 

    Verify client context handle.

Arguments:

    phContext - client context handle return from TLSRpcConnect().


Return:

    TRUE/FALSE

++*/
{
#if DBG

    BOOL bValid;
    LPCLIENTCONTEXT lpClientContext = (LPCLIENTCONTEXT)phContext;

    bValid = (lpClientContext->m_PreDbg[0] == 0xcdcdcdcd && lpClientContext->m_PreDbg[1] == 0xcdcdcdcd &&
              lpClientContext->m_PostDbg[0] == 0xcdcdcdcd && lpClientContext->m_PostDbg[1] == 0xcdcdcdcd);
    if(!bValid)
    {
        DBGPrintf(
                DBG_ERROR,
                DBG_FACILITY_RPC,
                DBGLEVEL_FUNCTION_TRACE,
                _TEXT("ValidContextHandle : Bad client context\n")
            );

        TLSASSERT(FALSE);
    }

    return bValid;

#else

    return TRUE;

#endif
}

//-------------------------------------------------------------------------

void 
__RPC_USER PCONTEXT_HANDLE_rundown(
    PCONTEXT_HANDLE phContext
    )
/*++

Description:

    Client context handle cleanup, called when client disconnect normally 
    or abnormally, see context handle rundown routine help on RPC

Argument:

    phContext - client context handle.

Returns:

    None

++*/
{
    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("PCONTEXT_HANDLE_rundown...\n")
        );

    TLSASSERT(phContext != NULL);

    try {
        
        //
        // If service is shutting down, exit right away without freeing up memory,
        //
        // Durning shutdown, RPC wait until all call completed but it does not wait
        // until all open connection has 'rundown' if client is still in enumeration,
        // this will cause ReleaseWorkSpace() to assert.  Instead of using one more
        // HANDLE to wait until all open connection has been rundown, we return right
        // away to speed up shutdown time
        //
        if( phContext && ValidContextHandle(phContext) )
        {
            LPCLIENTCONTEXT lpClientContext = (LPCLIENTCONTEXT)phContext;

            DBGPrintf(
                    DBG_INFORMATION,
                    DBG_FACILITY_RPC,
                    DBGLEVEL_FUNCTION_TRACE,
                    _TEXT("Disconnect from %s\n"),
                    lpClientContext->m_Client
                );            

            assert(lpClientContext->m_RefCount == 0);
        
            if( IsServiceShuttingdown() == FALSE )
            {
                switch(lpClientContext->m_ContextType)
                {
                    case CONTEXTHANDLE_LICENSE_ENUM_TYPE:
                        {
                            PTLSDbWorkSpace pDbWkSpace = (PTLSDbWorkSpace)lpClientContext->m_ContextHandle;

                            if( IsValidAllocatedWorkspace(pDbWkSpace) == TRUE )
                            {
                                ReleaseWorkSpace(&pDbWkSpace);
                            }
                        }
                        break;

                    case CONTEXTHANDLE_KEYPACK_ENUM_TYPE:
                        {
                            LPENUMHANDLE hEnum=(LPENUMHANDLE)lpClientContext->m_ContextHandle;

                            if( IsValidAllocatedWorkspace(hEnum->pbWorkSpace) == TRUE )
                            {
                                TLSDBLicenseKeyPackEnumEnd(hEnum);
                            }

                            lpClientContext->m_ContextType = CONTEXTHANDLE_EMPTY_TYPE;
                            lpClientContext->m_ContextHandle=NULL;
                        }
                        break;

                    case CONTEXTHANDLE_HYDRA_REQUESTCERT_TYPE:
                        {
                            LPTERMSERVCERTREQHANDLE lpHandle=(LPTERMSERVCERTREQHANDLE)lpClientContext->m_ContextHandle;
                            midl_user_free(lpHandle->pCertRequest);
                            midl_user_free(lpHandle->pbChallengeData);
                            FreeMemory(lpHandle);
                        }
                        break;

                    case CONTEXTHANDLE_CHALLENGE_SERVER_TYPE:
                    case CONTEXTHANDLE_CHALLENGE_LRWIZ_TYPE:
                    case CONTEXTHANDLE_CHALLENGE_TERMSRV_TYPE:
                        {
                            PTLSCHALLENGEDATA pChallengeData = (PTLSCHALLENGEDATA) lpClientContext->m_ContextHandle;
                            if(pChallengeData)
                            {
                                FreeMemory(pChallengeData->pbChallengeData);
                                FreeMemory(pChallengeData);
                            }
                        }
                }
            }
            else
            {
                DBGPrintf(
                    DBG_INFORMATION,
                    DBG_FACILITY_RPC,
                    DBGLEVEL_FUNCTION_TRACE,
                    _TEXT("PCONTEXT_HANDLE_rundown while shutting down...\n")
                );
            }                
 
            if( lpClientContext->m_Client )
            {
                FreeMemory(lpClientContext->m_Client);
            }

            midl_user_free(lpClientContext);
        }
    }
    catch(...) {
        SetLastError(TLS_E_INTERNAL);
    }

    return;
}


//----------------------------------------------------------------------------------
DWORD
GetClientPrivilege(
    IN handle_t hRpcBinding
    )

/*++
Description:

    Return client's privilege level

Arguments:
    
    hRpcBinding - Client's RPC binding handle.

Return:

    Client's privilege level

++*/
{
    DWORD dwStatus = CLIENT_ACCESS_USER;
    BOOL bAdmin=FALSE;
    RPC_STATUS rpc_status;

    // If a value of zero is specified, the server impersonates the client that 
    // is being served by this server thread
    rpc_status = RpcImpersonateClient(hRpcBinding);
    if(rpc_status == RPC_S_OK)
    {
        IsAdmin(&bAdmin);
        dwStatus = (bAdmin) ? CLIENT_ACCESS_ADMIN : CLIENT_ACCESS_USER;

        RpcRevertToSelfEx(hRpcBinding);
    }

    return dwStatus;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcConnect( 
    /* [in] */ handle_t binding,
    /* [out] */ PCONTEXT_HANDLE __RPC_FAR *pphContext
    )
/*++

Description:

    Connect client and allocate/return client context handle.

Arguments:

    hRPCBinding - RPC binding handle
    pphContext - client context handle.

Returns via dwErrCode.

    RPC_S_ACCESS_DENIED or LSERVER_S_SUCCESS.

++*/
{
    DWORD status=ERROR_SUCCESS;
    DWORD dwPriv;

    RPC_BINDING_HANDLE hClient=NULL;
    WCHAR * pszRpcStrBinding=NULL;
    LPTSTR pszClient=NULL;

    if(RpcBindingServerFromClient(binding, &hClient) == RPC_S_OK)
    {
        status = RpcBindingToStringBinding( hClient, &pszRpcStrBinding );
        RpcBindingFree(&hClient);

        if (status != RPC_S_OK)
        {
            goto cleanup;
        }
    }

    //
    // need to load from resource file
    //
    pszClient = (LPTSTR)AllocateMemory(
                            (_tcslen((pszRpcStrBinding) ? pszRpcStrBinding : _TEXT("Unknown")) + 1) * sizeof(TCHAR)
                        );

    if(pszClient == NULL)
    {
        status = ERROR_OUTOFMEMORY;
        goto cleanup;
    }

    _tcscpy(pszClient,
            (pszRpcStrBinding) ? pszRpcStrBinding : _TEXT("Unknown")
        );

    if(pszRpcStrBinding)
    {
        RpcStringFree(&pszRpcStrBinding);
    }
        
    DBGPrintf(
        DBG_INFORMATION,
        DBG_FACILITY_RPC,
        DBGLEVEL_FUNCTION_TRACE,
        _TEXT("Connect from client %s\n"), 
        pszClient
    );

    dwPriv=GetClientPrivilege(binding);

    LPCLIENTCONTEXT lpContext;

    lpContext=(LPCLIENTCONTEXT)midl_user_allocate(sizeof(CLIENTCONTEXT));
    if(lpContext == NULL)
    {
        status = ERROR_OUTOFMEMORY;
        goto cleanup;
    }

    #if DBG
    lpContext->m_LastCall = RPC_CALL_CONNECT;
    lpContext->m_PreDbg[0] = 0xcdcdcdcd;
    lpContext->m_PreDbg[1] = 0xcdcdcdcd;
    lpContext->m_PostDbg[0] = 0xcdcdcdcd;
    lpContext->m_PostDbg[1] = 0xcdcdcdcd;
    #endif

    lpContext->m_Client = pszClient;

    lpContext->m_RefCount = 0;
    *pphContext=lpContext;
    lpContext->m_ContextType = CONTEXTHANDLE_EMPTY_TYPE;
    lpContext->m_ClientFlags = dwPriv;

cleanup:

    if(status != ERROR_SUCCESS)
    {
        FreeMemory(pszClient);
    }

    return TLSMapReturnCode(status);
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcDisconnect( 
    /* [out][in] */ PPCONTEXT_HANDLE pphContext
    )
/*++

Description:

    Disconnect client and FreeMemory all memory allocated on the behalf of client         

Arguments:

    pphContext - pointer to client context handle

Returns:

    LSERVER_S_SUCCESS or ERROR_INVALID_HANDLE

++*/
{
    DWORD Status=ERROR_SUCCESS;

    try {

        if(!ValidContextHandle(*pphContext) || *pphContext == NULL)
        {
            Status = ERROR_INVALID_HANDLE;
        }
        else
        {
            PCONTEXT_HANDLE_rundown(*pphContext);
            *pphContext = NULL;
        }

    }
    catch(...) {
        Status = TLS_E_INTERNAL;
    }        
    
    return TLSMapReturnCode(Status);
}

//-------------------------------------------------------------------------------

error_status_t 
TLSRpcGetVersion( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out][in] */ PDWORD pdwVersion
    )
/*++

++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    InterlockedIncrement( &lpContext->m_RefCount );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetVersion\n"),
            lpContext->m_Client
        );

    if(TLSIsBetaNTServer() == TRUE)
    {
        *pdwVersion = TLS_CURRENT_VERSION;
    }
    else
    {
        *pdwVersion = TLS_CURRENT_VERSION_RTM;
    }

    if(g_SrvRole & TLSERVER_ENTERPRISE_SERVER)
    {
        *pdwVersion |= TLS_VERSION_ENTERPRISE_BIT;
    }

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_DETAILSIMPLE,
            _TEXT("%s : TLSRpcGetVersion return 0x%08x\n"),
            lpContext->m_Client,
            *pdwVersion
        );

    InterlockedDecrement( &lpContext->m_RefCount );
    return RPC_S_OK;
}


//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetSupportFlags( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out] */ DWORD *pdwSupportFlags
    )
/*++

++*/
{
    error_status_t status = RPC_S_OK;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;

    InterlockedIncrement( &lpContext->m_RefCount );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetSupportFlags\n"),
            lpContext->m_Client
        );

    if (NULL != pdwSupportFlags)
    {
        *pdwSupportFlags = ALL_KNOWN_SUPPORT_FLAGS;
    }
    else
    {
        status = ERROR_INVALID_PARAMETER;
    }

    InterlockedDecrement( &lpContext->m_RefCount );
    return status;
}

//-------------------------------------------------------------------------------

error_status_t 
TLSRpcSendServerCertificate( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD cbCert,
    /* [size_is][in] */ PBYTE pbCert,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    This routine is for License Server to identify hydra server, hydra server
    need to send its certificate in order to gain certificate request privilege.

Arguments:

    phContext - client context handle.
    cbCert - size of hydra server certificate.
    pbCert - hydra server's self-created certificate.
    dwErrCode - return code.

Returns via dwErrCode

    LSERVER_E_INVALID_DATA.

++*/
{
    DWORD status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    InterlockedIncrement( &lpContext->m_RefCount );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcSendServerCertificate\n"),
            lpContext->m_Client
        );

    try {

        if(pbCert == NULL || cbCert == 0 || 
           TLSVerifyHydraCertificate(pbCert, cbCert) != LICENSE_STATUS_OK)
        {
            DBGPrintf(
                    DBG_WARNING,
                    DBG_FACILITY_RPC,
                    DBGLEVEL_FUNCTION_DETAILSIMPLE,
                    _TEXT("TLSRpcSendServerCertificate : client %s send invalid certificate\n"),
                    lpContext->m_Client
                );

            status = TLS_E_INVALID_DATA;
        }
        else
        {
            lpContext->m_ClientFlags |= CLIENT_ACCESS_REQUEST;
        }

    }
    catch(...) {
        status = TLS_E_INVALID_DATA;
    }        

    // midl_user_free(pbCert);

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_SEND_CERTIFICATE;
    #endif

    *dwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetServerName( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [size_is][string][out][in] */ LPTSTR szMachineName,
    /* [out][in] */ PDWORD cbSize,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Return server's machine name. 

Arguments:

    phContext - Client context handle
    szMachineName - return server's machine name, must be at least
                    MAX_COMPUTERNAME_LENGTH + 1 in length

Return:

    TLS_E_INVALID_DATA - buffer size too small.

++*/
{
    // TODO: no need for this buffer - use caller's buffer instead

    TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+2];
    DWORD dwBufferSize=MAX_COMPUTERNAME_LENGTH+1;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;   

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetServerName\n"),
            lpContext->m_Client
        );

    if(lpContext->m_ContextType != CONTEXTHANDLE_CHALLENGE_SERVER_TYPE)
    {
        *dwErrCode = TLSMapReturnCode(TLS_E_INVALID_DATA);

        return RPC_S_OK;
    }

    *dwErrCode = ERROR_SUCCESS;
    if(!GetComputerName(szComputerName, &dwBufferSize))
    {
        *dwErrCode = GetLastError();
    }

    //
    // return buffer must be big enough for NULL, 
    // dwBufferSize return does not include NULL.
    //
    if(*cbSize <= dwBufferSize)
    {
        DBGPrintf(
                DBG_WARNING,
                DBG_FACILITY_RPC,
                DBGLEVEL_FUNCTION_DETAILSIMPLE,
                _TEXT("TLSRpcGetServerName : Client %s invalid parameter\n"),
                lpContext->m_Client
            );

        *dwErrCode = TLSMapReturnCode(TLS_E_INVALID_DATA);
    }
    else
    {
        _tcsncpy(szMachineName, szComputerName, min(_tcslen(szComputerName), *cbSize));
        szMachineName[min(_tcslen(szComputerName), *cbSize - 1)] = _TEXT('\0');
    }

    *cbSize = _tcslen(szComputerName) + 1; // include NULL terminate string

    #if DBG
    lpContext->m_LastCall = RPC_CALL_GET_SERVERNAME;
    #endif

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetServerNameEx( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [size_is][string][out][in] */ LPTSTR szMachineName,
    /* [out][in] */ PDWORD cbSize,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Return server's machine name. 

Arguments:

    phContext - Client context handle
    szMachineName - return server's machine name, must be at least
                    MAX_COMPUTERNAME_LENGTH + 1 in length

Return:

    TLS_E_INVALID_DATA - buffer size too small.

++*/
{
    // TODO: no need for this buffer - use caller's buffer instead

    TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+2];
    DWORD dwBufferSize=MAX_COMPUTERNAME_LENGTH+1;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetServerNameEx\n"),
            lpContext->m_Client
        );

    *dwErrCode = ERROR_SUCCESS;
    if(!GetComputerName(szComputerName, &dwBufferSize))
    {
        *dwErrCode = GetLastError();
    }

    //
    // return buffer must be big enough for NULL, 
    // dwBufferSize return does not include NULL.
    //
    if(*cbSize <= dwBufferSize)
    {
        DBGPrintf(
                DBG_WARNING,
                DBG_FACILITY_RPC,
                DBGLEVEL_FUNCTION_DETAILSIMPLE,
                _TEXT("TLSRpcGetServerNameEx : Client %s invalid parameter\n"),
                lpContext->m_Client
            );

        *dwErrCode = TLSMapReturnCode(TLS_E_INVALID_DATA);
    }
    else
    {
        _tcsncpy(szMachineName, szComputerName, min(_tcslen(szComputerName), *cbSize));
        szMachineName[min(_tcslen(szComputerName), *cbSize - 1)] = _TEXT('\0');
    }

    *cbSize = _tcslen(szComputerName) + 1; // include NULL terminate string

    #if DBG
    lpContext->m_LastCall = RPC_CALL_GET_SERVERNAME;
    #endif

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetServerScope( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [size_is][string][out][in] */ LPTSTR szScopeName,
    /* [out][in] */ PDWORD cbSize,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Return License Server's scope

Arguments:

    phContext - Client context
    szScopeName - return server's scope, must be at least 
                  MAX_COMPUTERNAME_LENGTH in length

Return:

    LSERVER_S_SUCCESS or error code from WideCharToMultiByte()
    TLS_E_INVALID_DATA - buffer size too small.

++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetServerScope\n"),
            lpContext->m_Client
        );

    *dwErrCode = ERROR_SUCCESS;
    if(*cbSize <= _tcslen(g_pszScope))
    {
        *dwErrCode = TLSMapReturnCode(TLS_E_INVALID_DATA);
    }
    else
    {
        _tcsncpy(szScopeName, g_pszScope, min(_tcslen(g_pszScope), *cbSize));
        szScopeName[min(_tcslen(g_pszScope), *cbSize-1)] = _TEXT('\0');
    }

    *cbSize = _tcslen(g_pszScope) + 1; // include NULL terminate string

    #if DBG
    lpContext->m_LastCall = RPC_CALL_GET_SERVERSCOPE;
    #endif
    
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetInfo( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD cbHSCert,
    /* [size_is][in] */ PBYTE pHSCert,
    /* [ref][out] */ DWORD __RPC_FAR *pcbLSCert,
    /* [size_is][size_is][out] */ BYTE __RPC_FAR *__RPC_FAR *pLSCert,
    /* [ref][out] */ DWORD __RPC_FAR *pcbLSSecretKey,
    /* [size_is][size_is][out] */ BYTE __RPC_FAR *__RPC_FAR *pLSSecretKey,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Routine to exchange Hydra server's certificate and License server's
    certificate/private key for signing client machine's hardware ID.

Arguments:

    phContext - client context handle
    cbHSCert - size of Hydra Server's certificate
    pHSCert - Hydra Server's certificate
    pcbLSCert - return size of License Server's certificate
    pLSCert - return License Server's certificate
    pcbLSSecretKey - return size of License Server's private key.
    pLSSecretKey - retrun License Server's private key

Return Value:  

    LSERVER_S_SUCCESS           success
    LSERVER_E_INVALID_DATA      Invalid hydra server certificate
    LSERVER_E_OUTOFMEMORY       Can't allocate required memory
    TLS_E_INTERNAL              Internal error occurred in License Server

++*/
{
    DWORD status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetInfo\n"),
            lpContext->m_Client
        );
    
    try {
        do {
            if( pHSCert == NULL || cbHSCert == 0 || 
                TLSVerifyHydraCertificate(pHSCert, cbHSCert) != LICENSE_STATUS_OK)
            {
                status= TLS_E_INVALID_DATA;
                break;
            }

            *pcbLSCert = g_cbSignatureEncodedCert;
            *pLSCert = (PBYTE)midl_user_allocate(*pcbLSCert);
            if(!*pLSCert)
            {
                status = ERROR_OUTOFMEMORY;
                break;
            }
            memcpy(*pLSCert, (PBYTE)g_pbSignatureEncodedCert, *pcbLSCert);
            
            *pcbLSSecretKey=0;
            *pLSSecretKey=NULL;
        } while(FALSE);

        if(status != ERROR_SUCCESS)
        {    
            if(*pLSCert)
                midl_user_free(*pLSCert);

            if(*pLSSecretKey)
                midl_user_free(*pLSSecretKey);

            *pcbLSCert=0;
            *pcbLSSecretKey=0;
            *pLSCert=NULL;
            *pLSSecretKey=NULL;
        }

    } 
    catch(...) {
        status = TLS_E_INTERNAL;
    }        

    // midl_user_free(pHSCert);

    #if DBG
    lpContext->m_LastCall = RPC_CALL_GETINFO;
    #endif

    lpContext->m_LastError = status;
    *dwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------

#define RANDOM_CHALLENGE_DATA   _TEXT("TEST")

DWORD
TLSGenerateChallengeData( 
    IN DWORD ClientInfo, 
    OUT PDWORD pcbChallengeData, 
    IN OUT PBYTE* pChallengeData
    )
{
    DWORD hr=ERROR_SUCCESS;

    *pcbChallengeData = (_tcslen(RANDOM_CHALLENGE_DATA) + 1) * sizeof(WCHAR);
    *pChallengeData=(PBYTE)midl_user_allocate(*pcbChallengeData);

    if(*pChallengeData)
    {
        memcpy(*pChallengeData, RANDOM_CHALLENGE_DATA, *pcbChallengeData);
    }
    else
    {
        SetLastError(hr=ERROR_OUTOFMEMORY);
    }

    return hr;
}

//++----------------------------------------------------------------------------
DWORD
TLSVerifyChallengeDataGetWantedLicenseLevel(
    IN const CHALLENGE_CONTEXT ChallengeContext,
    IN const DWORD cbChallengeData,
    IN const PBYTE pbChallengeData,
    OUT WORD* pwLicenseDetail
    )
/*++

--*/
{
    DWORD dwStatus = ERROR_SUCCESS;

    DWORD dwChallengeDataSize = (_tcslen(RANDOM_CHALLENGE_DATA) + 1) * sizeof(WCHAR);
    PPlatformChallengeResponseData pChallengeResponse;

    if( cbChallengeData < dwChallengeDataSize || pbChallengeData == NULL )
    {
        //
        // Assume old client, new client always send back our challenge data
        //
        *pwLicenseDetail = LICENSE_DETAIL_SIMPLE;
    }
    else if( cbChallengeData == dwChallengeDataSize &&
        _tcsicmp( (LPCTSTR)pbChallengeData, RANDOM_CHALLENGE_DATA ) == 0 )
    {
        //
        // old client, set license chain to LICENSE_DETAIL_SIMPLE
        //
        *pwLicenseDetail = LICENSE_DETAIL_SIMPLE;
    }
    else
    {
        BOOL bValidStruct = TRUE;

        //
        // we still don't have a good challenge so ignore actual verification
        //
        pChallengeResponse = (PPlatformChallengeResponseData) pbChallengeData;

        bValidStruct = (pChallengeResponse->wVersion == CURRENT_PLATFORMCHALLENGE_VERSION);
        if( bValidStruct == TRUE )
        {
            bValidStruct = (pChallengeResponse->cbChallenge + offsetof(PlatformChallengeResponseData, pbChallenge) == cbChallengeData);
        }

        if (bValidStruct == TRUE )
        {
            if( pChallengeResponse->wClientType == WIN32_PLATFORMCHALLENGE_TYPE ||
                pChallengeResponse->wClientType == WIN16_PLATFORMCHALLENGE_TYPE ||
                pChallengeResponse->wClientType == WINCE_PLATFORMCHALLENGE_TYPE ||
                pChallengeResponse->wClientType == OTHER_PLATFORMCHALLENGE_TYPE )
            {
                bValidStruct = TRUE;
            }
            else
            {
                bValidStruct = FALSE;
            }
        }
        
        if( bValidStruct == TRUE )
        {
            if( pChallengeResponse->wLicenseDetailLevel == LICENSE_DETAIL_SIMPLE ||
                pChallengeResponse->wLicenseDetailLevel == LICENSE_DETAIL_MODERATE ||
                pChallengeResponse->wLicenseDetailLevel == LICENSE_DETAIL_DETAIL )
            {
                bValidStruct = TRUE;
            }
            else
            {
                bValidStruct = FALSE;
            }
        }

        //
        // For now, we simply let it go thru, assert or deny request once
        // we settle down of challenge
        //
        if( bValidStruct == FALSE )
        {
            // bad data, assume old client
            *pwLicenseDetail = LICENSE_DETAIL_SIMPLE;
        }
        //else if( pChallengeResponse->wClientType == WINCE_PLATFORMCHALLENGE_TYPE )
        //{
            //
            // UN-comment this to limit WINCE to get a self-signed certificate
            //
        //    *pwLicenseDetail = LICENSE_DETAIL_SIMPLE;
        //}
        else
        {
            *pwLicenseDetail = pChallengeResponse->wLicenseDetailLevel;
        }
    }

    return dwStatus;
}


//++----------------------------------------------------------------------------
error_status_t 
TLSRpcIssuePlatformChallenge( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwClientInfo,
    /* [ref][out] */ PCHALLENGE_CONTEXT pChallengeContext,
    /* [out] */ PDWORD pcbChallengeData,
    /* [size_is][size_is][out] */ BYTE __RPC_FAR *__RPC_FAR *pChallengeData,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Issue a platform challenge to hydra client.

Arguments:

    phContext - client context handle
    dwClientInfo - client info.
    pChallengeContext - pointer to client challenge context.
    pcbChallengeData - size of challenge data.
    pChallengeData - random client challenge data.

Returns via dwErrCode:

    LSERVER_S_SUCCESS
    LSERVER_E_OUTOFMEMORY       Out of memory
    LSERVER_E_INVALID_DATA      Invalid client info.
    LSERVER_E_SERVER_BUSY       Server is busy

++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    LPCLIENTCHALLENGECONTEXT lpChallenge=NULL;
    DWORD status=ERROR_SUCCESS;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcIssuePlatformChallenge\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );
    try {

        do {
            status=TLSGenerateChallengeData(
                        dwClientInfo, 
                        pcbChallengeData, 
                        pChallengeData
                        );
            if(status != ERROR_SUCCESS)
            {
                break;
            }

            *pChallengeContext = dwClientInfo;
        } while (FALSE);

        if(status != ERROR_SUCCESS)
        {
            if(*pChallengeData)
            {
                midl_user_free(*pChallengeData);
                *pChallengeData = NULL;
            }

            *pcbChallengeData=0;
        }
    }
    catch(...) {
        status = TLS_E_INTERNAL;
    }        

    lpContext->m_LastError=status;

    #if DBG
    lpContext->m_LastCall = RPC_CALL_ISSUEPLATFORMCHLLENGE;
    #endif

    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcRequestNewLicense( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ const CHALLENGE_CONTEXT ChallengeContext,
    /* [in] */ TLSLICENSEREQUEST __RPC_FAR *pRequest,
    /* [string][in] */ LPTSTR szMachineName,
    /* [string][in] */ LPTSTR szUserName,
    /* [in] */ const DWORD cbChallengeResponse,
    /* [size_is][in] */ const PBYTE pbChallenge,
    /* [in] */ BOOL bAcceptTemporaryLicense,
    /* [out] */ PDWORD pcbLicense,
    /* [size_is][size_is][out] */ BYTE __RPC_FAR *__RPC_FAR *ppbLicense,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Description:

    Routine to issue new license to hydra client based on product requested, 
    it returns existing license if client already has a license and the 
    license is not expired/returned/revoked, if request product has not been 
    installed, it will issue a temporary license, if license found is temporary 
    or expired, it will tried to upgrade/re-issue a new license with latest 
    version of requested product, if the existing license is temporary and 
    no license can be issued, it returns LSERVER_E_LICENSE_EXPIRED


Arguments:

    phContext - client context handle.
    ChallengeContext - client challenge context handle, return from 
                       call TLSRpcIssuePlatformChallenge()
    pRequest - product license request.
    pMachineName - client's machine name.
    pUserName - client user name.
    cbChallengeResponse - size of the client's response to license server's
                          platform challenge.
    pbChallenge - client's response to license server's platform challenge
    bAcceptTemporaryLicense - TRUE if client wants temp. license FALSE otherwise.
    pcbLicense - size of return license.
    ppLicense - return license, could be old license

Return Value:

    LSERVER_S_SUCCESS
    LSERVER_E_OUTOFMEMORY
    LSERVER_E_SERVER_BUSY       Server is busy to process request.
    LSERVER_E_INVALID_DATA      Invalid platform challenge response.
    LSERVER_E_NO_LICENSE        No license available.
    LSERVER_E_NO_PRODUCT        Request product is not installed on server.
    LSERVER_E_LICENSE_REJECTED  License request is rejected by cert. server
    LSERVER_E_LICENSE_REVOKED   Old license found and has been revoked
    LSERVER_E_LICENSE_EXPIRED   Request product's license has expired
    LSERVER_E_CORRUPT_DATABASE  Corrupted database.
    LSERVER_E_INTERNAL_ERROR    Internal error in license server
    LSERVER_I_PROXIMATE_LICENSE Closest match license returned.
    LSERVER_I_TEMPORARY_LICENSE Temporary license has been issued
    LSERVER_I_LICENSE_UPGRADED  Old license has been upgraded.
++*/
{
    DWORD dwSupportFlags = 0;
    
    return TLSRpcRequestNewLicenseEx( 
                                     phContext,
                                     &dwSupportFlags,
                                     ChallengeContext,
                                     pRequest,
                                     szMachineName,
                                     szUserName,
                                     cbChallengeResponse,
                                     pbChallenge,
                                     bAcceptTemporaryLicense,
                                     1,         // dwQuantity
                                     pcbLicense,
                                     ppbLicense,
                                     pdwErrCode
                                     );
}

error_status_t 
TLSRpcRequestNewLicenseEx(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in, out] */ DWORD *pdwSupportFlags,
    /* [in] */ const CHALLENGE_CONTEXT ChallengeContext,
    /* [in] */ TLSLICENSEREQUEST __RPC_FAR *pRequest,
    /* [string][in] */ LPTSTR szMachineName,
    /* [string][in] */ LPTSTR szUserName,
    /* [in] */ const DWORD cbChallengeResponse,
    /* [size_is][in] */ const PBYTE pbChallenge,
    /* [in] */ BOOL bAcceptTemporaryLicense,
    /* [in] */ DWORD dwQuantity,
    /* [out] */ PDWORD pcbLicense,
    /* [size_is][size_is][out] */ BYTE __RPC_FAR *__RPC_FAR *ppbLicense,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Description:

    Routine to issue new license to hydra client based on product requested
    and input support flags.

    *pdwSupportFlags == 0:
        it returns existing license if client already has a license and the 
        license is not expired/returned/revoked, if request product has not
        been installed, it will issue a temporary license, if license found is
        temporary or expired, it will tried to upgrade/re-issue a new license
        with latest version of requested product, if the existing license is
        temporary and no license can be issued, it returns
        LSERVER_E_LICENSE_EXPIRED

    *pdwSupportFlags & SUPPORT_PER_SEAT_POST_LOGON:
        For non-per-seat licenses, it behaves as if the flag wasn't set.
        For per-seat licenses, if bAcceptTemporaryLicense is TRUE, it always
        returns a temporary license.  If bAcceptTemporaryLicense if FALSE, it
        returns LSERVER_E_NO_LICENSE.

Arguments:

    phContext - client context handle.
    pdwSupportFlags - on input, abilities supported by TS.  on output,
                      abilities supported by both TS and LS
    ChallengeContext - client challenge context handle, return from 
                       call TLSRpcIssuePlatformChallenge()
    pRequest - product license request.
    pMachineName - client's machine name.
    pUserName - client user name.
    cbChallengeResponse - size of the client's response to license server's
                          platform challenge.
    pbChallenge - client's response to license server's platform challenge
    bAcceptTemporaryLicense - TRUE if client wants temp. license FALSE
                              otherwise.
    dwQuantity - number of licenses to allocate
    pcbLicense - size of return license.
    ppLicense - return license, could be old license

Return Value:

    LSERVER_S_SUCCESS
    LSERVER_E_OUTOFMEMORY
    LSERVER_E_SERVER_BUSY       Server is busy to process request.
    LSERVER_E_INVALID_DATA      Invalid platform challenge response.
    LSERVER_E_NO_LICENSE        No license available.
    LSERVER_E_NO_PRODUCT        Request product is not installed on server.
    LSERVER_E_LICENSE_REJECTED  License request is rejected by cert. server
    LSERVER_E_LICENSE_REVOKED   Old license found and has been revoked
    LSERVER_E_LICENSE_EXPIRED   Request product's license has expired
    LSERVER_E_CORRUPT_DATABASE  Corrupted database.
    LSERVER_E_INTERNAL_ERROR    Internal error in license server
    LSERVER_I_PROXIMATE_LICENSE Closest match license returned.
    LSERVER_I_TEMPORARY_LICENSE Temporary license has been issued
    LSERVER_I_LICENSE_UPGRADED  Old license has been upgraded.
++*/
{
    return TLSRpcRequestNewLicenseExEx( 
                                     phContext,
                                     pdwSupportFlags,
                                     ChallengeContext,
                                     pRequest,
                                     szMachineName,
                                     szUserName,
                                     cbChallengeResponse,
                                     pbChallenge,
                                     bAcceptTemporaryLicense,
                                     FALSE,     // bAcceptFewerLicense
                                     &dwQuantity,
                                     pcbLicense,
                                     ppbLicense,
                                     pdwErrCode
                                     );
}

error_status_t 
TLSRpcRequestNewLicenseExEx(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in, out] */ DWORD *pdwSupportFlags,
    /* [in] */ const CHALLENGE_CONTEXT ChallengeContext,
    /* [in] */ TLSLICENSEREQUEST __RPC_FAR *pRequest,
    /* [string][in] */ LPTSTR szMachineName,
    /* [string][in] */ LPTSTR szUserName,
    /* [in] */ const DWORD cbChallengeResponse,
    /* [size_is][in] */ const PBYTE pbChallenge,
    /* [in] */ BOOL bAcceptTemporaryLicense,
    /* [in] */ BOOL bAcceptFewerLicenses,
    /* [in,out] */ DWORD *pdwQuantity,
    /* [out] */ PDWORD pcbLicense,
    /* [size_is][size_is][out] */ BYTE __RPC_FAR *__RPC_FAR *ppbLicense,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Description:

    Routine to issue new license to hydra client based on product requested
    and input support flags.

    *pdwSupportFlags == 0:
        it returns existing license if client already has a license and the 
        license is not expired/returned/revoked, if request product has not
        been installed, it will issue a temporary license, if license found is
        temporary or expired, it will tried to upgrade/re-issue a new license
        with latest version of requested product, if the existing license is
        temporary and no license can be issued, it returns
        LSERVER_E_LICENSE_EXPIRED

    *pdwSupportFlags & SUPPORT_PER_SEAT_POST_LOGON:
        For non-per-seat licenses, it behaves as if the flag wasn't set.
        For per-seat licenses, if bAcceptTemporaryLicense is TRUE, it always
        returns a temporary license.  If bAcceptTemporaryLicense if FALSE, it
        returns LSERVER_E_NO_LICENSE.

Arguments:

    phContext - client context handle.
    pdwSupportFlags - on input, abilities supported by TS.  on output,
                      abilities supported by both TS and LS
    ChallengeContext - client challenge context handle, return from 
                       call TLSRpcIssuePlatformChallenge()
    pRequest - product license request.
    pMachineName - client's machine name.
    pUserName - client user name.
    cbChallengeResponse - size of the client's response to license server's
                          platform challenge.
    pbChallenge - client's response to license server's platform challenge
    bAcceptTemporaryLicense - TRUE if client wants temp. license FALSE
                              otherwise.
    bAcceptFewerLicenses - TRUE if succeeding with fewer licenses than
                           requested is acceptable
    pdwQuantity - on input, number of licenses to allocate.  on output,
                  number of licenses actually allocated
    pcbLicense - size of return license.
    ppLicense - return license, could be old license

Return Value:

    LSERVER_S_SUCCESS
    LSERVER_E_OUTOFMEMORY
    LSERVER_E_SERVER_BUSY       Server is busy to process request.
    LSERVER_E_INVALID_DATA      Invalid platform challenge response.
    LSERVER_E_NO_LICENSE        No license available.
    LSERVER_E_NO_PRODUCT        Request product is not installed on server.
    LSERVER_E_LICENSE_REJECTED  License request is rejected by cert. server
    LSERVER_E_LICENSE_REVOKED   Old license found and has been revoked
    LSERVER_E_LICENSE_EXPIRED   Request product's license has expired
    LSERVER_E_CORRUPT_DATABASE  Corrupted database.
    LSERVER_E_INTERNAL_ERROR    Internal error in license server
    LSERVER_I_PROXIMATE_LICENSE Closest match license returned.
    LSERVER_I_TEMPORARY_LICENSE Temporary license has been issued
    LSERVER_I_LICENSE_UPGRADED  Old license has been upgraded.
++*/
{
    PMHANDLE        hClient;
    DWORD           status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;

    TCHAR szUnknown[LSERVER_MAX_STRING_SIZE+1];
    TCHAR szClientMachineName[LSERVER_MAX_STRING_SIZE];
    TCHAR szClientUserName[LSERVER_MAX_STRING_SIZE];
    TCHAR szCompanyName[LSERVER_MAX_STRING_SIZE+1];
    TCHAR szProductId[LSERVER_MAX_STRING_SIZE+1];

    TLSForwardNewLicenseRequest Forward;
    TLSDBLICENSEREQUEST LsLicenseRequest;
    CTLSPolicy* pPolicy=NULL;

    PMLICENSEREQUEST PMLicenseRequest;
    PPMLICENSEREQUEST pAdjustedRequest;
    BOOL bForwardRequest = TRUE;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    #ifdef DBG
    DWORD dwStartTime=GetTickCount();
    #endif

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcRequestNewLicense\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    if ((NULL == pdwQuantity) || (0 == *pdwQuantity))
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    if(VerifyLicenseRequest(pRequest) == FALSE)
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    if(NULL == pdwSupportFlags)
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    *pdwSupportFlags &= ALL_KNOWN_SUPPORT_FLAGS;

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_REQUEST))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    if(lpContext->m_ClientFlags == CLIENT_ACCESS_LSERVER)
    {
        //
        // do not forward any request or infinite loop might
        // occur.
        //
        bForwardRequest = FALSE;
    }

    Forward.m_ChallengeContext = ChallengeContext;
    Forward.m_pRequest = pRequest;
    Forward.m_szMachineName = szMachineName;
    Forward.m_szUserName = szUserName;
    Forward.m_cbChallengeResponse = cbChallengeResponse;
    Forward.m_pbChallengeResponse = pbChallenge;

    memset(szCompanyName, 0, sizeof(szCompanyName));
    memset(szProductId, 0, sizeof(szProductId));

    memcpy(
            szCompanyName,
            pRequest->ProductInfo.pbCompanyName,
            min(pRequest->ProductInfo.cbCompanyName, sizeof(szCompanyName)-sizeof(TCHAR))
        );

    memcpy(
            szProductId,
            pRequest->ProductInfo.pbProductID,
            min(pRequest->ProductInfo.cbProductID, sizeof(szProductId)-sizeof(TCHAR))
        );

    //
    // Acquire policy module, a default policy module will
    // be returned.
    //
    pPolicy = AcquirePolicyModule(
                            szCompanyName, //(LPCTSTR)pRequest->ProductInfo.pbCompanyName,
                            szProductId,    //(LPCTSTR)pRequest->ProductInfo.pbProductID
                            FALSE
                        );

    if(pPolicy == NULL)
    {
        status = TLS_E_INTERNAL;
        goto cleanup;
    }

    hClient = GenerateClientId();

    //
    // return error if string is too big.
    // 
    LoadResourceString(
            IDS_UNKNOWN_STRING, 
            szUnknown, 
            sizeof(szUnknown)/sizeof(szUnknown[0])
            );

    _tcsncpy(szClientMachineName, 
             (szMachineName) ? szMachineName : szUnknown,
             LSERVER_MAX_STRING_SIZE
            );

    szClientMachineName[LSERVER_MAX_STRING_SIZE-1] = 0;

    _tcsncpy(szClientUserName, 
             (szUserName) ? szUserName : szUnknown,
             LSERVER_MAX_STRING_SIZE
            );

    szClientUserName[LSERVER_MAX_STRING_SIZE-1] = 0;

    //
    // Convert request to PMLICENSEREQUEST
    //
    TlsLicenseRequestToPMLicenseRequest(
                        LICENSETYPE_LICENSE,
                        pRequest,
                        szClientMachineName,
                        szClientUserName,
                        *pdwSupportFlags,
                        &PMLicenseRequest
                    );

    //
    // Inform Policy module start of new license request
    //
    status = pPolicy->PMLicenseRequest(
                                hClient,
                                REQUEST_NEW,
                                (PVOID) &PMLicenseRequest,
                                (PVOID *) &pAdjustedRequest
                            );

    if(status != ERROR_SUCCESS)
    {
        goto cleanup;
    }

    if(pAdjustedRequest != NULL)
    {
        if(_tcsicmp(PMLicenseRequest.pszCompanyName,pAdjustedRequest->pszCompanyName) != 0)
        {                               
            // try to steal license from other company???
            TLSLogEvent(
                    EVENTLOG_ERROR_TYPE,
                    TLS_E_POLICYERROR,
                    status = TLS_E_POLICYMODULEERROR,
                    pPolicy->GetCompanyName(),
                    pPolicy->GetProductId()
                );

            goto cleanup;
        }
    }
    else
    {
        pAdjustedRequest = &PMLicenseRequest;
    }

    //
    // form DB request structure
    //
    status = TLSFormDBRequest(
                            pRequest->pbEncryptedHwid, 
                            pRequest->cbEncryptedHwid,
                            pAdjustedRequest->dwProductVersion,
                            pAdjustedRequest->pszCompanyName,
                            pAdjustedRequest->pszProductId,
                            pAdjustedRequest->dwLanguageId,
                            pAdjustedRequest->dwPlatformId,
                            pAdjustedRequest->pszMachineName,
                            pAdjustedRequest->pszUserName,
                            &LsLicenseRequest
                        );

    if(status != ERROR_SUCCESS)
    {
        goto cleanup;
    }

    LsLicenseRequest.pPolicy = pPolicy;
    LsLicenseRequest.hClient = hClient;
    LsLicenseRequest.pPolicyLicenseRequest = pAdjustedRequest;
    LsLicenseRequest.pClientLicenseRequest = &PMLicenseRequest;

    try {
        status = TLSVerifyChallengeDataGetWantedLicenseLevel(
                                    ChallengeContext,
                                    cbChallengeResponse,
                                    pbChallenge,
                                    &LsLicenseRequest.wLicenseDetail
                                );
    
        if( status == ERROR_SUCCESS )
        {
            status = TLSNewLicenseRequest(
                            bForwardRequest,
                            pdwSupportFlags,
                            &Forward,
                            &LsLicenseRequest,
                            bAcceptTemporaryLicense,
                            pAdjustedRequest->fTemporary,
                            TRUE,       // bFindLostLicense
                            bAcceptFewerLicenses,
                            pdwQuantity,
                            pcbLicense,
                            ppbLicense
                        );
        }
    }
    catch( SE_Exception e ) {
        status = e.getSeNumber();
    }
    catch(...) {
        status = TLS_E_INTERNAL;
    }

cleanup:

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_ISSUENEWLICENSE;
    #endif

    #ifdef DBG
    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_DETAILSIMPLE,
            _TEXT("\t%s : TLSRpcRequestNewLicense() takes %dms\n"),
            lpContext->m_Client,
            GetTickCount() - dwStartTime
        );
    #endif
    
    *pdwErrCode = TLSMapReturnCode(status);

    if(pPolicy)
    {
        pPolicy->PMLicenseRequest(
                            hClient,
                            REQUEST_COMPLETE,
                            UlongToPtr(status),
                            NULL
                        );
        
        ReleasePolicyModule(pPolicy);
    }

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcUpgradeLicense( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ TLSLICENSEREQUEST __RPC_FAR *pRequest,
    /* [in] */ const CHALLENGE_CONTEXT ChallengeContext,
    /* [in] */ const DWORD cbChallengeResponse,
    /* [size_is][in] */ const PBYTE pbChallenge,
    /* [in] */ DWORD cbOldLicense,
    /* [size_is][in] */ PBYTE pbOldLicense,
    /* [out] */ PDWORD pcbNewLicense,
    /* [size_is][size_is][out] */ PBYTE __RPC_FAR *ppbNewLicense,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Update an old license.

Arguments:


Return Value:  

    LSERVER_S_SUCCESS
    TLS_E_INTERNAL
    LSERVER_E_INTERNAL_ERROR
    LSERVER_E_INVALID_DATA      old license is invalid.
    LSERVER_E_NO_LICENSE        no available license
    LSERVER_E_NO_PRODUCT        request product not install in current server.
    LSERVER_E_CORRUPT_DATABASE  Corrupted database.
    LSERVER_E_LICENSE_REJECTED  License request rejected by cert. server.
    LSERVER_E_SERVER_BUSY

++*/
{
    DWORD dwSupportFlags = 0;

    return TLSRpcUpgradeLicenseEx( 
                                  phContext,
                                  &dwSupportFlags,
                                  pRequest,
                                  ChallengeContext,
                                  cbChallengeResponse,
                                  pbChallenge,
                                  cbOldLicense,
                                  pbOldLicense,
                                  1,    // dwQuantity
                                  pcbNewLicense,
                                  ppbNewLicense,
                                  dwErrCode
                                  );

}
//-------------------------------------------------------------------------------
error_status_t 
TLSRpcUpgradeLicenseEx( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in,out] */ DWORD *pdwSupportFlags,
    /* [in] */ TLSLICENSEREQUEST __RPC_FAR *pRequest,
    /* [in] */ const CHALLENGE_CONTEXT ChallengeContext,
    /* [in] */ const DWORD cbChallengeResponse,
    /* [size_is][in] */ const PBYTE pbChallenge,
    /* [in] */ DWORD cbOldLicense,
    /* [size_is][in] */ PBYTE pbOldLicense,
    /* [in] */ DWORD dwQuantity,
    /* [out] */ PDWORD pcbNewLicense,
    /* [size_is][size_is][out] */ PBYTE __RPC_FAR *ppbNewLicense,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Update an old license.  Behavior varies depending on product requested,
    the old license, and input support flags.

    *pdwSupportFlags == 0:
        it returns existing license if client already has a current-version
        license and the license is not expired/returned/revoked. if requested
        product has not been installed, it will issue a temporary license (if
        the client doesn't already have one). if old license is temporary
        or expired, it will try to upgrade/re-issue a new license
        with latest version of requested product. if the existing license is
        temporary and no license can be issued, it returns
        LSERVER_E_LICENSE_EXPIRED

    *pdwSupportFlags & SUPPORT_PER_SEAT_POST_LOGON:
        For non-per-seat licenses, it behaves as if the flag wasn't set.
        For per-seat licenses, if the old license isn't current-version
        temporary, it also behaves as if the flag wasn't set.
        Otherwise, it checks that the temporary license was marked as having
        been authenticated.  If so, it tries to issue a permanent license.
        If a license can't be issued, or if he temporary license wasn't marked,
        it returns the old license.

Arguments:

    phContext - client context handle.
    pdwSupportFlags - on input, abilities supported by TS.  on output,
                      abilities supported by both TS and LS
    pRequest - product license request.
    ChallengeContext - client challenge context handle, return from 
                       call TLSRpcIssuePlatformChallenge()
    cbChallengeResponse - size of the client's response to license server's
                          platform challenge.
    pbChallenge - client's response to license server's platform challenge
    cbOldLicense - size of old license.
    pbOldLicense - old license
    dwQuantity - number of licenses to allocate
    pcbNewLicense - size of return license.
    ppbNewLicense - return license, could be old license

Return Value:  

    LSERVER_S_SUCCESS
    TLS_E_INTERNAL
    LSERVER_E_INTERNAL_ERROR
    LSERVER_E_INVALID_DATA      old license is invalid.
    LSERVER_E_NO_LICENSE        no available license
    LSERVER_E_NO_PRODUCT        request product not install in current server.
    LSERVER_E_CORRUPT_DATABASE  Corrupted database.
    LSERVER_E_LICENSE_REJECTED  License request rejected by cert. server.
    LSERVER_E_SERVER_BUSY

++*/
{
    DWORD status = ERROR_SUCCESS;
    BOOL bTemporaryLicense; 
    PMUPGRADEREQUEST pmRequestUpgrade;
    PMLICENSEREQUEST pmLicenseRequest;
    PPMLICENSEREQUEST pmAdjustedRequest;
    PPMLICENSEDPRODUCT ppmLicensedProduct=NULL;
    DWORD dwNumLicensedProduct=0;
    PLICENSEDPRODUCT pLicensedProduct=NULL;
    TLSDBLICENSEREQUEST LsLicenseRequest;
    PMHANDLE hClient;
    CTLSPolicy* pPolicy=NULL;
    DWORD dwNumPermLicense;
    DWORD dwNumTempLicense;
    TLSForwardUpgradeLicenseRequest Forward;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    LICENSEDCLIENT license;
    LICENSEPACK keypack;
    DWORD index;
    BOOL bForwardRequest = TRUE;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );
    
    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcUpgradeLicense\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    if (1 != dwQuantity)
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    if(VerifyLicenseRequest(pRequest) == FALSE)
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    if(NULL == pdwSupportFlags)
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    *pdwSupportFlags &= ALL_KNOWN_SUPPORT_FLAGS;

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_REQUEST))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    if(lpContext->m_ClientFlags == CLIENT_ACCESS_LSERVER)
    {
        //
        // do not forward any request or infinite loop might
        // occur.
        //
        bForwardRequest = FALSE;
    }

    //
    // Convert blob to licensed product structure
    //
    status = LSVerifyDecodeClientLicense(
                            pbOldLicense, 
                            cbOldLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            NULL
                        );

    if(status != LICENSE_STATUS_OK || dwNumLicensedProduct == 0)
    {
        status = TLS_E_INVALID_LICENSE;
        goto cleanup;
    }

    pLicensedProduct = (PLICENSEDPRODUCT)AllocateMemory(
                                                    dwNumLicensedProduct * sizeof(LICENSEDPRODUCT)
                                                );
    if(pLicensedProduct == NULL)
    {
        status = TLS_E_ALLOCATE_MEMORY;
        goto cleanup;
    }

    status = LSVerifyDecodeClientLicense(
                            pbOldLicense, 
                            cbOldLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            pLicensedProduct
                        );

    if(status != LICENSE_STATUS_OK)
    {
        status = TLS_E_INVALID_LICENSE;
        goto cleanup;
    }

    //
    // Verify licensed product array.
    //
    for(index = 1; index < dwNumLicensedProduct; index++)
    {
        //
        // licensed product array always sorted in decending order
        //

        //
        // Product ID in original request in licensed product must 
        // be the same otherwise invalid license.
        //
        if(pLicensedProduct->cbOrgProductID != (pLicensedProduct-1)->cbOrgProductID)
        {
            status = TLS_E_INVALID_LICENSE;
            break;
        }

        if( memcmp(
                pLicensedProduct->pbOrgProductID, 
                (pLicensedProduct-1)->pbOrgProductID,
                pLicensedProduct->cbOrgProductID) != 0 )
        {
            status = TLS_E_INVALID_LICENSE;
            goto cleanup;
        }

        if( (pLicensedProduct->pLicensedVersion->dwFlags & LICENSED_VERSION_TEMPORARY) )
        {
            //
            // only latest licensed version can be temporary
            //
            status = TLS_E_INVALID_LICENSE;
            goto cleanup;
        }
    }

    //
    // Find the policy module
    // 
    hClient = GenerateClientId();

    TCHAR szCompanyName[LSERVER_MAX_STRING_SIZE+1];
    TCHAR szProductId[LSERVER_MAX_STRING_SIZE+1];

    memset(szCompanyName, 0, sizeof(szCompanyName));
    memset(szProductId, 0, sizeof(szProductId));

    memcpy(
            szCompanyName,
            pRequest->ProductInfo.pbCompanyName,
            min(pRequest->ProductInfo.cbCompanyName, sizeof(szCompanyName)-sizeof(TCHAR))
        );

    memcpy(
            szProductId,
            pRequest->ProductInfo.pbProductID,
            min(pRequest->ProductInfo.cbProductID, sizeof(szProductId)-sizeof(TCHAR))
        );

    //
    // Acquire policy module, a default policy module will
    // be returned.
    //
    pPolicy = AcquirePolicyModule(
                        szCompanyName,  // (LPCTSTR) pLicensedProduct->LicensedProduct.pProductInfo->pbCompanyName,
                        szProductId,     // (LPCTSTR) pLicensedProduct->pbOrgProductID
                        FALSE
                    );

    if(pPolicy == NULL)
    {
        //
        // Must have a policy module, default policy module always there
        //
        status = TLS_E_INTERNAL;
        goto cleanup;
    }

    //
    // Convert request to PMLICENSEREQUEST
    //
    TlsLicenseRequestToPMLicenseRequest(
                        LICENSETYPE_LICENSE,
                        pRequest,
                        pLicensedProduct->szLicensedClient,
                        pLicensedProduct->szLicensedUser,
                        *pdwSupportFlags,
                        &pmLicenseRequest
                    );

    //
    // generate PMUPGRADEREQUEST and pass it to Policy Module
    //
    memset(&pmRequestUpgrade, 0, sizeof(pmRequestUpgrade));

    ppmLicensedProduct = (PPMLICENSEDPRODUCT)AllocateMemory(sizeof(PMLICENSEDPRODUCT)*dwNumLicensedProduct);
    if(ppmLicensedProduct == NULL)
    {
        status = TLS_E_ALLOCATE_MEMORY;
        goto cleanup;
    }

    for(index=0; index < dwNumLicensedProduct; index++)
    {
        ppmLicensedProduct[index].pbData = 
                        pLicensedProduct[index].pbPolicyData;

        ppmLicensedProduct[index].cbData = 
                        pLicensedProduct[index].cbPolicyData;

        ppmLicensedProduct[index].bTemporary = 
                        ((pLicensedProduct[index].pLicensedVersion->dwFlags & LICENSED_VERSION_TEMPORARY) != 0);

        // treat license issued from beta server as temporary
        if(ppmLicensedProduct[index].bTemporary == FALSE && TLSIsBetaNTServer() == FALSE)
        {
            if(IS_LICENSE_ISSUER_RTM(pLicensedProduct[index].pLicensedVersion->dwFlags) == FALSE)
            {
                ppmLicensedProduct[index].bTemporary = TRUE;
            }
        }

        ppmLicensedProduct[index].ucMarked = 0;

        if (0 == index)
        {
            // for first license, check markings on license
            status = TLSCheckLicenseMarkRequest(
                            TRUE,   // forward request if necessary
                            pLicensedProduct,
                            cbOldLicense,
                            pbOldLicense,
                            &(ppmLicensedProduct[index].ucMarked)
                            );
        }

        ppmLicensedProduct[index].LicensedProduct.dwProductVersion = 
                        pLicensedProduct[index].LicensedProduct.pProductInfo->dwVersion;

        ppmLicensedProduct[index].LicensedProduct.pszProductId = 
                        (LPTSTR)(pLicensedProduct[index].LicensedProduct.pProductInfo->pbProductID);

        ppmLicensedProduct[index].LicensedProduct.pszCompanyName = 
                        (LPTSTR)(pLicensedProduct[index].LicensedProduct.pProductInfo->pbCompanyName);

        ppmLicensedProduct[index].LicensedProduct.dwLanguageId = 
                        pLicensedProduct[index].LicensedProduct.dwLanguageID;

        ppmLicensedProduct[index].LicensedProduct.dwPlatformId = 
                        pLicensedProduct[index].LicensedProduct.dwPlatformID;

        ppmLicensedProduct[index].LicensedProduct.pszMachineName = 
                        pLicensedProduct[index].szLicensedClient;

        ppmLicensedProduct[index].LicensedProduct.pszUserName = 
                        pLicensedProduct[index].szLicensedUser;
    }

    pmRequestUpgrade.pbOldLicense = pbOldLicense;
    pmRequestUpgrade.cbOldLicense = cbOldLicense;
    pmRequestUpgrade.pUpgradeRequest = &pmLicenseRequest;

    pmRequestUpgrade.dwNumProduct = dwNumLicensedProduct;
    pmRequestUpgrade.pProduct = ppmLicensedProduct;
    
    status = pPolicy->PMLicenseUpgrade(
                                hClient,
                                REQUEST_UPGRADE,
                                (PVOID)&pmRequestUpgrade,
                                (PVOID *) &pmAdjustedRequest
                            );

    if(status != ERROR_SUCCESS)
    {
        goto cleanup;
    }

    if(pmAdjustedRequest != NULL)
    {
        if(_tcsicmp(
                    pmLicenseRequest.pszCompanyName, 
                    pmAdjustedRequest->pszCompanyName
                ) != 0)
        { 
            //                              
            // Try to steal license from other company???
            //
            TLSLogEvent(
                    EVENTLOG_ERROR_TYPE,
                    TLS_E_POLICYERROR,
                    status = TLS_E_POLICYMODULEERROR,
                    pPolicy->GetCompanyName(),
                    pPolicy->GetProductId()
                );

            goto cleanup;
        }
    }
    else
    {
        pmAdjustedRequest = &pmLicenseRequest;
    }

    for(index =0; index < dwNumLicensedProduct; index++)
    {
        DWORD tExpireDate;

        FileTimeToLicenseDate(&(pLicensedProduct[index].NotAfter),
            &tExpireDate);

        if( CompareTLSVersions(pmAdjustedRequest->dwProductVersion, pLicensedProduct[index].LicensedProduct.pProductInfo->dwVersion) <= 0 &&
            !(pLicensedProduct[index].pLicensedVersion->dwFlags & LICENSED_VERSION_TEMPORARY) &&
            _tcscmp(pmAdjustedRequest->pszProductId, (LPTSTR)(pLicensedProduct[index].LicensedProduct.pProductInfo->pbProductID)) == 0 &&
            tExpireDate-g_dwReissueLeaseLeeway >= ((DWORD)time(NULL)) )
        {
            if( TLSIsBetaNTServer() == TRUE ||
                IS_LICENSE_ISSUER_RTM(pLicensedProduct[index].pLicensedVersion->dwFlags) == TRUE )
            {
                //
                // Blob already contain perm. license that is >= version
                // requested.
                //
                *ppbNewLicense = (PBYTE)midl_user_allocate(cbOldLicense);
                if(*ppbNewLicense != NULL)
                {
                    memcpy(*ppbNewLicense, pbOldLicense, cbOldLicense);
                    *pcbNewLicense = cbOldLicense;
                    status = ERROR_SUCCESS;
                }
                else
                {
                    status = TLS_E_ALLOCATE_MEMORY;
                }

                goto cleanup;
            }
        }
    }
    
    memset(&LsLicenseRequest, 0, sizeof(TLSDBLICENSEREQUEST));

    status = TLSFormDBRequest(
                            pRequest->pbEncryptedHwid, 
                            pRequest->cbEncryptedHwid,
                            pmAdjustedRequest->dwProductVersion,
                            pmAdjustedRequest->pszCompanyName,
                            pmAdjustedRequest->pszProductId,
                            pmAdjustedRequest->dwLanguageId,
                            pmAdjustedRequest->dwPlatformId,
                            pmAdjustedRequest->pszMachineName,
                            pmAdjustedRequest->pszUserName,
                            &LsLicenseRequest
                        );

    if(status != ERROR_SUCCESS)
    {
        goto cleanup;
    }

    LsLicenseRequest.pPolicy = pPolicy;
    LsLicenseRequest.hClient = hClient;
    LsLicenseRequest.pPolicyLicenseRequest = pmAdjustedRequest;
    LsLicenseRequest.pClientLicenseRequest = &pmLicenseRequest;
    
    memset(&keypack, 0, sizeof(keypack));

    try {

        status = TLSVerifyChallengeDataGetWantedLicenseLevel(
                                    ChallengeContext,
                                    cbChallengeResponse,
                                    pbChallenge,
                                    &LsLicenseRequest.wLicenseDetail
                                );

        if( status == ERROR_SUCCESS )
        {

            //
            // if client challenge context handle is 0xFFFFFFFF,
            // cbChallenge = 0 and pbChallenge is NULL.
            // client is old version, don't verify challenge
            //            
            Forward.m_pRequest = pRequest;
            Forward.m_ChallengeContext = ChallengeContext;
            Forward.m_cbChallengeResponse = cbChallengeResponse;
            Forward.m_pbChallengeResponse = pbChallenge;
            Forward.m_cbOldLicense = cbOldLicense;
            Forward.m_pbOldLicense = pbOldLicense;

            status = TLSUpgradeLicenseRequest(
                                bForwardRequest,
                                &Forward,
                                pdwSupportFlags,
                                &LsLicenseRequest,
                                pbOldLicense,
                                cbOldLicense,
                                dwNumLicensedProduct,
                                pLicensedProduct,
                                pmAdjustedRequest->fTemporary,
                                pcbNewLicense,
                                ppbNewLicense
                            );
        }

    } // end try
    catch( SE_Exception e ) {
        status = e.getSeNumber();
    }
    catch(...) 
    {
        status = TLS_E_INTERNAL;
    }

cleanup:

    FreeMemory(ppmLicensedProduct);

    for(index =0; index < dwNumLicensedProduct; index++)
    {
        LSFreeLicensedProduct(pLicensedProduct+index);
    }

    FreeMemory(pLicensedProduct);

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_UPGRADELICENSE;
    #endif
    
    *dwErrCode = TLSMapReturnCode(status);

    if(pPolicy)
    {
        pPolicy->PMLicenseRequest(
                            hClient,
                            REQUEST_COMPLETE,
                            UlongToPtr (status),
                            NULL
                        );
        
        ReleasePolicyModule(pPolicy);
    }

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-----------------------------------------------------------------------------
error_status_t
TLSRpcCheckLicenseMark(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ const DWORD  cbLicense,
    /* [in, size_is(cbLicense)] */ PBYTE   pbLicense,
    /* [out] */ UCHAR *pucMarkFlags,
    /* [in, out, ref] */ PDWORD pdwErrCode
    )
/*++

Description:

    Check markings on the passed in license

Arguments:

    phContext - client context handle
    cbLicense - size of license to be checked
    pbLicense - license to be checked
    pucMarkFlags - markings on license

Return via pdwErrCode:
    LSERVER_S_SUCCESS
    LSERVER_E_INVALID_DATA      Invalid parameter.
    LSERVER_E_INVALID_LICENSE   License passed in is bad
    LSERVER_E_DATANOTFOUND      license not found in database
    LSERVER_E_CORRUPT_DATABASE  Corrupt database
    LSERVER_E_INTERNAL_ERROR    Internal error in license server

Note:
    This function forwards the request to the issuing license server.  If
    the issuer isn't available, or doesn't have the license in the database,
    it searches in the local database for a license with the same HWID.

++*/
{
    DWORD status = ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD dwNumLicensedProduct = 0;
    PLICENSEDPRODUCT pLicensedProduct=NULL;
    DWORD index;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );
    
    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcCheckLicenseMark\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_LSERVER))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    if (NULL == pucMarkFlags)
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    //
    // Convert blob to licensed product structure
    //
    status=LSVerifyDecodeClientLicense(
                            pbLicense, 
                            cbLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            NULL        // find size to allocate
                        );

    if(status != LICENSE_STATUS_OK || dwNumLicensedProduct == 0)
    {
        status = TLS_E_INVALID_LICENSE;
        goto cleanup;
    }

    pLicensedProduct = (PLICENSEDPRODUCT)AllocateMemory(
                               dwNumLicensedProduct * sizeof(LICENSEDPRODUCT)
                               );

    if(pLicensedProduct == NULL)
    {
        status = TLS_E_ALLOCATE_MEMORY;
        goto cleanup;
    }

    status=LSVerifyDecodeClientLicense(
                            pbLicense, 
                            cbLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            pLicensedProduct
                        );

    if(status != LICENSE_STATUS_OK)
    {
        status = TLS_E_INVALID_LICENSE;
        goto cleanup;
    }

    try {

        status = TLSCheckLicenseMarkRequest(
                           FALSE,       // don't forward the request
                           pLicensedProduct,
                           cbLicense,
                           pbLicense,
                           pucMarkFlags
                           );
    } // end try
    catch( SE_Exception e ) {
        status = e.getSeNumber();
    }
    catch(...) 
    {
        status = TLS_E_INTERNAL;
    }


cleanup:

    for(index =0; index < dwNumLicensedProduct; index++)
    {
        LSFreeLicensedProduct(pLicensedProduct+index);
    }

    FreeMemory(pLicensedProduct);

    lpContext->m_LastError=status;

    *pdwErrCode = TLSMapReturnCode(status);

    InterlockedDecrement( &lpContext->m_RefCount );

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-----------------------------------------------------------------------------
error_status_t
TLSRpcMarkLicense(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ UCHAR ucMarkFlags,
    /* [in] */ const DWORD  cbLicense,
    /* [in, size_is(cbLicense)] */ PBYTE   pbLicense,
    /* [in, out, ref] */ PDWORD pdwErrCode
    )
/*++

Description:

    Set markings on the passed in license

Arguments:

    phContext - client context handle
    ucMarkFlags - markings on license
    cbLicense - size of license to be checked
    pbLicense - license to be checked

Return via pdwErrCode:
    LSERVER_S_SUCCESS
    LSERVER_E_INVALID_DATA      Invalid parameter.
    LSERVER_E_INVALID_LICENSE   License passed in is bad
    LSERVER_E_DATANOTFOUND      license not found in database
    LSERVER_E_CORRUPT_DATABASE  Corrupt database
    LSERVER_E_INTERNAL_ERROR    Internal error in license server

Note:
    This function forwards the request to the issuing license server.  The
    issuer modifies the database entry of the license to set the markings.

++*/
{
    DWORD status = ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    BOOL bForwardRequest = TRUE;
    DWORD dwNumLicensedProduct = 0;
    PLICENSEDPRODUCT pLicensedProduct=NULL;
    DWORD index;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );
    
    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcMarkLicense\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_REQUEST))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    if(lpContext->m_ClientFlags == CLIENT_ACCESS_LSERVER)
    {
        //
        // do not forward any request or infinite loop might
        // occur.
        //
        bForwardRequest = FALSE;
    }

    //
    // Convert blob to licensed product structure
    //
    status=LSVerifyDecodeClientLicense(
                            pbLicense, 
                            cbLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            NULL        // find size to allocate
                        );

    if(status != LICENSE_STATUS_OK || dwNumLicensedProduct == 0)
    {
        status = TLS_E_INVALID_LICENSE;
        goto cleanup;
    }

    pLicensedProduct = (PLICENSEDPRODUCT)AllocateMemory(
                               dwNumLicensedProduct * sizeof(LICENSEDPRODUCT)
                               );

    if(pLicensedProduct == NULL)
    {
        status = TLS_E_ALLOCATE_MEMORY;
        goto cleanup;
    }

    status=LSVerifyDecodeClientLicense(
                            pbLicense, 
                            cbLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            pLicensedProduct
                        );

    if(status != LICENSE_STATUS_OK)
    {
        status = TLS_E_INVALID_LICENSE;
        goto cleanup;
    }

    try {

        status = TLSMarkLicenseRequest(
                           bForwardRequest,
                           ucMarkFlags,
                           pLicensedProduct,
                           cbLicense,
                           pbLicense
                           );
    } // end try
    catch( SE_Exception e ) {
        status = e.getSeNumber();
    }
    catch(...) 
    {
        status = TLS_E_INTERNAL;
    }


cleanup:

    for(index =0; index < dwNumLicensedProduct; index++)
    {
        LSFreeLicensedProduct(pLicensedProduct+index);
    }

    FreeMemory(pLicensedProduct);

    lpContext->m_LastError=status;

    *pdwErrCode = TLSMapReturnCode(status);

    InterlockedDecrement( &lpContext->m_RefCount );

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcAllocateConcurrentLicense( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [string][in] */ LPTSTR szHydraServer,
    /* [in] */ TLSLICENSEREQUEST __RPC_FAR *pRequest,
    /* [ref][out][in] */ LONG __RPC_FAR *pdwQuantity,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Description:

    Allocate concurrent licenses base on product.

Arguments:

    phContext - client context handle
    szHydraServer - name of hydra server requesting concurrent licenses
    pRequest - product to request for concurrent license.
    dwQuantity - See note

Return via dwErrCode:
    LSERVER_S_SUCCESS
    LSERVER_E_INVALID_DATA      Invalid parameter.
    LSERVER_E_NO_PRODUCT        request product not installed
    LSERVER_E_NO_LICNESE        no available license for request product 
    LSERVER_E_LICENSE_REVOKED   Request license has been revoked
    LSERVER_E_LICENSE_EXPIRED   Request license has expired
    LSERVER_E_CORRUPT_DATABASE  Corrupt database
    LSERVER_E_INTERNAL_ERROR    Internal error in license server

Note:
    dwQuantity
    Input                       Output
    -------------------------   -----------------------------------------
    0                           Total number of concurrent license 
                                issued to hydra server.
    > 0, number of license      Actual number of license allocated
         requested
    < 0, number of license      Actual number of license returned, always
         to return              positive value.

++*/
{
#if 1

    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;

#else

    PMHANDLE hClient;

    DWORD status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    PTLSDbWorkSpace pDbWorkSpace;

    TLSDBLICENSEREQUEST LsLicenseRequest;
    TCHAR szUnknown[LSERVER_MAX_STRING_SIZE+1];
    TCHAR szClientMachineName[LSERVER_MAX_STRING_SIZE];
    TCHAR szClientUserName[LSERVER_MAX_STRING_SIZE];
    TCHAR szCompanyName[LSERVER_MAX_STRING_SIZE+1];
    TCHAR szProductId[LSERVER_MAX_STRING_SIZE+1];

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    CTLSPolicy* pPolicy = NULL;
    BOOL bAllocateLicense = TRUE;

    PMLICENSEREQUEST PMLicenseRequest;
    PPMLICENSEREQUEST pAdjustedRequest;

    #ifdef DBG
    DWORD dwStartTime=GetTickCount();
    #endif


    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcAllocateConcurrentLicense\n"),
            lpContext->m_Client
        );

    if(*pdwQuantity > 1)
    {
        TLSASSERT(*pdwQuantity > 1);
    }

    InterlockedIncrement( &lpContext->m_RefCount );

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_REQUEST))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    memset(szCompanyName, 0, sizeof(szCompanyName));
    memset(szProductId, 0, sizeof(szProductId));

    memcpy(
            szCompanyName,
            pRequest->ProductInfo.pbCompanyName,
            min(pRequest->ProductInfo.cbCompanyName, sizeof(szCompanyName)-sizeof(TCHAR))
        );

    memcpy(
            szProductId,
            pRequest->ProductInfo.pbProductID,
            min(pRequest->ProductInfo.cbProductID, sizeof(szProductId)-sizeof(TCHAR))
        );

    //
    // Acquire policy module, a default policy module will
    // be returned.
    //
    pPolicy = AcquirePolicyModule(
                            szCompanyName, //(LPCTSTR)pRequest->ProductInfo.pbCompanyName,
                            szProductId,   //(LPCTSTR)pRequest->ProductInfo.pbProductID
                            TRUE
                        );

    if(pPolicy == NULL)
    {
        status = GetLastError();
        goto cleanup;
    }

    hClient = GenerateClientId();

    //
    // return error if string is too big.
    // 
    LoadResourceString(
                IDS_UNKNOWN_STRING, 
                szUnknown, 
                sizeof(szUnknown)/sizeof(szUnknown[0])
            );

    _tcsncpy(
            szClientMachineName, 
            (szHydraServer) ? szHydraServer : szUnknown,
            LSERVER_MAX_STRING_SIZE
        );

    _tcsncpy(
            szClientUserName, 
            (szHydraServer) ? szHydraServer : szUnknown,
            LSERVER_MAX_STRING_SIZE
        );

    //
    // Convert request to PMLICENSEREQUEST
    //
    TlsLicenseRequestToPMLicenseRequest(
                        LICENSETYPE_LICENSE,
                        pRequest,
                        szClientMachineName,
                        szClientUserName,
                        0,
                        &PMLicenseRequest
                    );

    //
    // Inform Policy module start of new license request
    //
    status = pPolicy->PMLicenseRequest(
                                hClient,
                                REQUEST_NEW,
                                (PVOID) &PMLicenseRequest,
                                (PVOID *) &pAdjustedRequest
                            );

    if(status != ERROR_SUCCESS)
    {
        goto cleanup;
    }

    if(pAdjustedRequest != NULL)
    {
        if(_tcsicmp(PMLicenseRequest.pszCompanyName,pAdjustedRequest->pszCompanyName) != 0)
        {                               
            // try to steal license from other company???
            TLSLogEvent(
                    EVENTLOG_ERROR_TYPE,
                    TLS_E_POLICYERROR,
                    status = TLS_E_POLICYMODULEERROR,
                    pPolicy->GetCompanyName(),
                    pPolicy->GetProductId()
                );

            goto cleanup;
        }
    }
    else
    {
        pAdjustedRequest = &PMLicenseRequest;
    }


    //
    // form DB request structure
    //
    status = TLSFormDBRequest(
                            pRequest->pbEncryptedHwid, 
                            pRequest->cbEncryptedHwid,
                            pAdjustedRequest->dwProductVersion,
                            pAdjustedRequest->pszCompanyName,
                            pAdjustedRequest->pszProductId,
                            pAdjustedRequest->dwLanguageId,
                            pAdjustedRequest->dwPlatformId,
                            pAdjustedRequest->pszMachineName,
                            pAdjustedRequest->pszUserName,
                            &LsLicenseRequest
                        );

    if(status != ERROR_SUCCESS)
    {
        goto cleanup;
    }

    LsLicenseRequest.pPolicy = pPolicy;
    LsLicenseRequest.hClient = hClient;
    LsLicenseRequest.pPolicyLicenseRequest = pAdjustedRequest;
    LsLicenseRequest.pClientLicenseRequest = &PMLicenseRequest;
    
    if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
    {
        status=TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    bAllocateLicense = (*pdwQuantity) > 0;

    CLEANUPSTMT;

    BEGIN_TRANSACTION(pDbWorkSpace);

    try {
        status = TLSDBAllocateConcurrentLicense( 
                                USEHANDLE(pDbWorkSpace),
                                szHydraServer, 
                                &LsLicenseRequest, 
                                pdwQuantity 
                            );
    } 
    catch( SE_Exception e ) {
        status = e.getSeNumber();
    }
    catch(...) {
        SetLastError(status = TLS_E_INTERNAL);
    }
    
    if(TLS_ERROR(status))
    {
        ROLLBACK_TRANSACTION(pDbWorkSpace);
    }
    else
    {
        COMMIT_TRANSACTION(pDbWorkSpace);
    }

    FREEDBHANDLE(pDbWorkSpace);


cleanup:

    #if DBG
    lpContext->m_LastCall = RPC_CALL_ALLOCATECONCURRENT;
    #endif

    #ifdef DBG
    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_DETAILSIMPLE,
            _TEXT("\t%s : TLSRpcRequestNewLicense() takes %dms\n"),
            lpContext->m_Client,
            GetTickCount() - dwStartTime
        );
    #endif
    
    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);

    if(pPolicy)
    {
        pPolicy->PMLicenseRequest(
                            hClient,
                            REQUEST_COMPLETE,
                            (PVOID) status,
                            NULL
                        );
        
        ReleasePolicyModule(pPolicy);
    }

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);
    return RPC_S_OK;

#endif
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetLastError( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out][in] */ PDWORD cbBufferSize,
    /* [size_is][string][out][in] */ LPTSTR szBuffer,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Return error description text for client's last LSXXX call

Arguments:

    IN phContext - Client context
    IN cbBufferSize - max. size of szBuffer
    IN OUT szBuffer - Pointer to a buffer to receive the 
                      null-terminated character string containing 
                      error description

Returns via dwErrCode:
    LSERVER_S_SUCCESS

    TLS_E_INTERNAL     No error or can't find corresponding error
                       description.

    Error code from WideCharToMultiByte().

++*/
{
    DWORD status=ERROR_SUCCESS;
    LPTSTR lpMsgBuf=NULL;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;


    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetLastError\n"),
            lpContext->m_Client
        );

    try {
        DWORD dwRet;
        dwRet=FormatMessage( 
                        FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM | 
                                FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                        NULL,
                        lpContext->m_LastError,
                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                        (LPTSTR) &lpMsgBuf,
                        0,
                        NULL
                    );
        if(dwRet == 0)
        {
            status = GetLastError();
        }
        else
        {
            _tcsncpy(
                    szBuffer, 
                    (LPTSTR)lpMsgBuf, 
                    min(_tcslen((LPTSTR)lpMsgBuf), *cbBufferSize-1)
                );
            szBuffer[min(_tcslen((LPTSTR)lpMsgBuf), *cbBufferSize-1)] = _TEXT('\0');
            *cbBufferSize = _tcslen(szBuffer) + 1;
        }
    }
    catch(...) {
        status = TLS_E_INTERNAL;
    }        

    if(lpMsgBuf)
        LocalFree(lpMsgBuf);

    #if DBG
    lpContext->m_LastCall = RPC_CALL_GET_LASTERROR;
    #endif
  
    lpContext->m_LastError=status;
    *dwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcKeyPackEnumBegin( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwSearchParm,
    /* [in] */ BOOL bMatchAll,
    /* [ref][in] */ LPLSKeyPackSearchParm lpSearchParm,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Function to begin enumerate through all key pack installed on server
    based on search criterial.

Arguments:

    phContext - client context handle.
    dwSearchParm - search criterial.
    bMatchAll - match all search criterial.
    lpSearchParm - search parameter.

Return Value:  

LSERVER_S_SUCCESS
LSERVER_E_SERVER_BUSY       Server is too busy to process request
LSERVER_E_OUTOFMEMORY
TLS_E_INTERNAL
LSERVER_E_INTERNAL_ERROR    
LSERVER_E_INVALID_DATA      Invalid data in search parameter
LSERVER_E_INVALID_SEQUENCE  Invalid calling sequence, likely, previous
                            enumeration has not ended.
++*/
{

    DWORD status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    InterlockedIncrement( &lpContext->m_RefCount );
    _se_translator_function old_trans_se_func = NULL;

    old_trans_se_func = _set_se_translator( trans_se_func );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcKeyPackEnumBegin\n"),
            lpContext->m_Client
        );

    //
    // This will use cached db connection, in-consistency may occurred,
    // visibility of changes in one connection may not appear right away
    // on another connection handle, this is expected behavoir for Jet and
    // so are we, user can always re-fresh.
    //
    do {
        if(lpContext->m_ContextType != CONTEXTHANDLE_EMPTY_TYPE)
        {
            SetLastError(status=TLS_E_INVALID_SEQUENCE);
            break;
        }

        try {

            LPENUMHANDLE hEnum;

            hEnum = TLSDBLicenseKeyPackEnumBegin( 
                                        bMatchAll, 
                                        dwSearchParm, 
                                        lpSearchParm 
                                    );
            if(hEnum)
            {
                lpContext->m_ContextType = CONTEXTHANDLE_KEYPACK_ENUM_TYPE;
                lpContext->m_ContextHandle = (PVOID)hEnum;
            }
            else
            {
                status = GetLastError();
            }
        } 
        catch( SE_Exception e ) {
            status = e.getSeNumber();
        }
        catch(...) {
            status = TLS_E_INTERNAL;
        }        

    } while(FALSE);

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_KEYPACKENUMBEGIN;
    #endif

    *dwErrCode = TLSMapReturnCode(status);
    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcKeyPackEnumNext( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out] */ LPLSKeyPack lpKeyPack,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Return next key pack that match search criterial

Arguments:

    phContext - client context handle
    lpKeyPack - key pack that match search criterial

Return Value:  

    LSERVER_S_SUCCESS
    LSERVER_I_NO_MORE_DATA      No more keypack match search criterial
    TLS_E_INTERNAL     General error in license server
    LSERVER_E_INTERNAL_ERROR    Internal error in license server
    LSERVER_E_SERVER_BUSY       License server is too busy to process request
    LSERVER_E_OUTOFMEMORY       Can't process request due to insufficient memory
    LSERVER_E_INVALID_SEQUENCE  Invalid calling sequence, must call
                                LSKeyPackEnumBegin().

++*/
{
    DWORD status = ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    BOOL bShowAll = FALSE;


    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcKeyPackEnumNext\n"),
            lpContext->m_Client
        );


    InterlockedIncrement( &lpContext->m_RefCount );

    if(lpContext->m_ClientFlags == CLIENT_ACCESS_LSERVER)
    {
        bShowAll = TRUE;
    }

    // this one might cause access violation
    memset(lpKeyPack, 0, sizeof(LSKeyPack));

    if(lpContext->m_ContextType != CONTEXTHANDLE_KEYPACK_ENUM_TYPE)
    {
        SetLastError(status=TLS_E_INVALID_SEQUENCE);
    }
    else
    {
        do {
            try {
                LPENUMHANDLE hEnum=(LPENUMHANDLE)lpContext->m_ContextHandle;
                status=TLSDBLicenseKeyPackEnumNext( 
                                        hEnum, 
                                        lpKeyPack,
                                        bShowAll
                                    );
            }
            catch( SE_Exception e ) {
                status = e.getSeNumber();
            }
            catch(...) {
                status = TLS_E_INTERNAL;
            }
        } while(status == TLS_I_MORE_DATA);
    }

    lpContext->m_LastError=GetLastError();
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_KEYPACKENUMNEXT;
    #endif

    *dwErrCode = TLSMapReturnCode(status);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcKeyPackEnumEnd( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

++*/
{
    DWORD status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;


    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcKeyPackEnumEnd\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    try {
        if(lpContext->m_ContextType != CONTEXTHANDLE_KEYPACK_ENUM_TYPE)
        {
            SetLastError(status=ERROR_INVALID_HANDLE);
        }
        else
        {
            LPENUMHANDLE hEnum=(LPENUMHANDLE)lpContext->m_ContextHandle;

            TLSDBLicenseKeyPackEnumEnd(hEnum);
            lpContext->m_ContextType = CONTEXTHANDLE_EMPTY_TYPE;
            lpContext->m_ContextHandle=NULL;
        }
    }
    catch(...) {
        status = TLS_E_INTERNAL;
    }        

    lpContext->m_LastError=GetLastError();
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_KEYPACKENUMEND;
    #endif

    *dwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcKeyPackAdd( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out][in] */ LPLSKeyPack lpKeypack,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Add a license key pack.

Arguments:

    phContext - client context handle.
    lpKeyPack - key pack to be added.
    
Return Value:  

    LSERVER_S_SUCCESS
    LSERVER_E_INTERNAL_ERROR
    TLS_E_INTERNAL
    LSERVER_E_SERVER_BUSY
    LSERVER_E_DUPLICATE             Product already installed.
    LSERVER_E_INVALID_DATA
    LSERVER_E_CORRUPT_DATABASE

Note:

    Application must call LSKeyPackSetStatus() to activate keypack

++*/
{
    PTLSDbWorkSpace pDbWkSpace=NULL;
    DWORD status=ERROR_SUCCESS;

    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    InterlockedIncrement( &lpContext->m_RefCount );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcKeyPackAdd\n"),
            lpContext->m_Client
        );


    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_ADMIN))
    {
        status = TLS_E_ACCESS_DENIED;
    }
    else
    {
        if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
        {
            status=TLS_E_ALLOCATE_HANDLE;
        }
        else   
        {
            CLEANUPSTMT;

            BEGIN_TRANSACTION(pDbWkSpace);

            try {
                if(lpKeypack->ucKeyPackStatus == LSKEYPACKSTATUS_ADD_LICENSE ||
                   lpKeypack->ucKeyPackStatus == LSKEYPACKSTATUS_REMOVE_LICENSE)
                {
                    status = TLSDBLicenseKeyPackUpdateLicenses( 
                                                USEHANDLE(pDbWkSpace), 
                                                lpKeypack->ucKeyPackStatus == LSKEYPACKSTATUS_ADD_LICENSE,
                                                lpKeypack 
                                            );
                }
                else
                {
                    status = TLSDBLicenseKeyPackAdd( 
                                            USEHANDLE(pDbWkSpace), 
                                            lpKeypack 
                                        );
                }

                if(status == ERROR_SUCCESS)
                {
                    if( _tcsicmp( lpKeypack->szCompanyName, PRODUCT_INFO_COMPANY_NAME ) == 0 )
                    {
                        //
                        // check with known termsrv product ID.
                        //
                        if( _tcsnicmp(  lpKeypack->szProductId, 
                                        TERMSERV_PRODUCTID_SKU, 
                                        _tcslen(TERMSERV_PRODUCTID_SKU)) == 0 )
                        {
                            TLSResetLogLowLicenseWarning(
                                                    lpKeypack->szCompanyName,
                                                    TERMSERV_PRODUCTID_SKU, 
                                                    MAKELONG(lpKeypack->wMinorVersion, lpKeypack->wMajorVersion),
                                                    FALSE
                                                );
                        }
                        else if(_tcsnicmp(  lpKeypack->szProductId, 
                                            TERMSERV_PRODUCTID_INTERNET_SKU, 
                                            _tcslen(TERMSERV_PRODUCTID_INTERNET_SKU)) == 0 )
                        {
                            TLSResetLogLowLicenseWarning(
                                                    lpKeypack->szCompanyName,
                                                    TERMSERV_PRODUCTID_INTERNET_SKU, 
                                                    MAKELONG(lpKeypack->wMinorVersion, lpKeypack->wMajorVersion),
                                                    FALSE
                                                );
                        }
                        else
                        {
                            TLSResetLogLowLicenseWarning(
                                                    lpKeypack->szCompanyName,
                                                    lpKeypack->szProductId, 
                                                    MAKELONG(lpKeypack->wMinorVersion, lpKeypack->wMajorVersion),
                                                    FALSE
                                                );
                        }
                    }
                    else
                    {
                        TLSResetLogLowLicenseWarning(
                                                lpKeypack->szCompanyName,
                                                lpKeypack->szProductId, 
                                                MAKELONG(lpKeypack->wMinorVersion, lpKeypack->wMajorVersion),
                                                FALSE
                                            );
                    }
                }
            }
            catch(...) {
                status = TLS_E_INTERNAL;
            }

            if(TLS_ERROR(status))
            {
                ROLLBACK_TRANSACTION(pDbWkSpace);
            }
            else
            {
                COMMIT_TRANSACTION(pDbWkSpace);
            }
        
            FREEDBHANDLE(pDbWkSpace);
        }
    }

    //
    // Post a sync work object
    //
    if( status == ERROR_SUCCESS )
    {
        if( lpKeypack->ucKeyPackType != LSKEYPACKTYPE_FREE )
        {
            if(TLSAnnounceLKPToAllRemoteServer(
                                        lpKeypack->dwKeyPackId,
                                        0
                                    ) != ERROR_SUCCESS)
            {
                TLSLogWarningEvent(TLS_W_ANNOUNCELKP_FAILED);
            }
        }
    }

    #if DBG
    lpContext->m_LastCall = RPC_CALL_KEYPACKADD;
    #endif

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcKeyPackSetStatus( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwSetParm,
    /* [ref][in] */ LPLSKeyPack lpKeyPack,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Routine to activate/deactivated a key pack.

Arguments:

    phContext - client context handle
    dwSetParam - type of key pack status to be set.
    lpKeyPack - new key pack status.

Return Value:  

    LSERVER_S_SUCCESS
    LSERVER_E_INTERNAL_ERROR
    TLS_E_INTERNAL
    LSERVER_E_INVALID_DATA     
    LSERVER_E_SERVER_BUSY
    LSERVER_E_DATANOTFOUND      Key pack is not in server
    LSERVER_E_CORRUPT_DATABASE

++*/
{
    PTLSDbWorkSpace pDbWkSpace=NULL;

    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;

    InterlockedIncrement( &lpContext->m_RefCount );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcKeyPackSetStatus\n"),
            lpContext->m_Client
        );

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_ADMIN))
    {
        status = TLS_E_ACCESS_DENIED;
    }
    else if( (dwSetParm & ~(LSKEYPACK_SET_KEYPACKSTATUS | LSKEYPACK_SET_ACTIVATEDATE | LSKEYPACK_SET_EXPIREDATE)) &&
             !(lpContext->m_ClientFlags & CLIENT_ACCESS_LRWIZ) ) 
    {
        status = TLS_E_INVALID_DATA;
    }
    else
    {
        if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
        {
            status=TLS_E_ALLOCATE_HANDLE;
        }
        else   
        {
            CLEANUPSTMT;

            BEGIN_TRANSACTION(pDbWkSpace);

            try {
                status=TLSDBLicenseKeyPackSetStatus( 
                                        USEHANDLE(pDbWkSpace), 
                                        dwSetParm, 
                                        lpKeyPack 
                                    );
            }
            catch(...) {
                status = TLS_E_INTERNAL;
            }

            if(TLS_ERROR(status))
            {
                ROLLBACK_TRANSACTION(pDbWkSpace);
            }
            else
            {
                COMMIT_TRANSACTION(pDbWkSpace);
            }

            FREEDBHANDLE(pDbWkSpace);
        }
    }

    #if DBG
    lpContext->m_LastCall = RPC_CALL_KEYPACKSETSTATUS;
    #endif

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcLicenseEnumBegin( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwSearchParm,
    /* [in] */ BOOL bMatchAll,
    /* [ref][in] */ LPLSLicenseSearchParm lpSearchParm,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Description:

    Begin enumeration of license issued based on search criterial

Arguments:

    phContext - client context handle
    dwSearchParm - license search criterial.
    bMatchAll - match all search criterial
    lpSearchParm - license(s) to be enumerated.

Return Value:  

    Same as LSKeyPackEnumBegin().

++*/
{
    PTLSDbWorkSpace pDbWkSpace = NULL;
    DWORD status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcLicenseEnumBegin\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    //
    // This will use cached db connection, in-consistency may occurred,
    // visibility of changes in one connection may not appear right away
    // on another connection handle, this is expected behavoir for Jet and
    // so are we, user can always re-fresh.
    //

    do {
        if(lpContext->m_ContextType != CONTEXTHANDLE_EMPTY_TYPE)
        {
            SetLastError(status=TLS_E_INVALID_SEQUENCE);
            break;
        }

        pDbWkSpace = AllocateWorkSpace(g_EnumDbTimeout);

        // allocate ODBC connections
        if(pDbWkSpace == NULL)
        {
            status=TLS_E_ALLOCATE_HANDLE;
            break;
        }

        try {   
            LICENSEDCLIENT license;

            ConvertLSLicenseToLicense(lpSearchParm, &license);
            status = TLSDBLicenseEnumBegin( 
                                pDbWkSpace, 
                                bMatchAll, 
                                dwSearchParm & LICENSE_TABLE_EXTERN_SEARCH_MASK, 
                                &license 
                            );
        }
        catch( SE_Exception e ) {
            status = e.getSeNumber();
        }
        catch(...) {
            status = TLS_E_INTERNAL;
        }

        if(status == ERROR_SUCCESS)
        {
            lpContext->m_ContextType = CONTEXTHANDLE_LICENSE_ENUM_TYPE;
            lpContext->m_ContextHandle = (PVOID)pDbWkSpace;
        }
    } while(FALSE);

    if(status != ERROR_SUCCESS)
    {
        if(pDbWkSpace)
        {
            ReleaseWorkSpace(&pDbWkSpace);
        }
    }

    #if DBG
    lpContext->m_LastCall = RPC_CALL_LICENSEENUMBEGIN;
    #endif

    InterlockedDecrement( &lpContext->m_RefCount );
    lpContext->m_LastError=status;
    *dwErrCode = TLSMapReturnCode(status);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcLicenseEnumNext( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out] */ LPLSLicense lpLicense,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Abstract:

    Fetch next record match enumeration criterial.

Parameters:

    phContext : Client context handle.
    lpLicense : return next record that match enumeration criterial.
    dwErrCode : error code.

Returns:

    Function returns RPC status, dwErrCode return error code.

Note:

    Must have call TLSRpcLicenseEnumBegin().

++*/
{
    DWORD status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    InterlockedIncrement( &lpContext->m_RefCount );
    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcLicenseEnumNext\n"),
            lpContext->m_Client
        );

    if(lpContext->m_ContextType != CONTEXTHANDLE_LICENSE_ENUM_TYPE)
    {
        SetLastError(status=TLS_E_INVALID_SEQUENCE);
    }
    else
    {
        PTLSDbWorkSpace pDbWkSpace=(PTLSDbWorkSpace)lpContext->m_ContextHandle;
        try {
            LICENSEDCLIENT license;

            memset(lpLicense, 0, sizeof(LSLicense));

            status=TLSDBLicenseEnumNext( 
                                pDbWkSpace, 
                                &license
                            );
            if(status == ERROR_SUCCESS)
            {
                ConvertLicenseToLSLicense(&license, lpLicense);
            }
        } 
        catch( SE_Exception e ) {
            status = e.getSeNumber();
        }
        catch(...) {
            status = TLS_E_INTERNAL;
        }        
    }

    #if DBG
    lpContext->m_LastCall = RPC_CALL_LICENSEENUMNEXT;
    #endif
   
    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcLicenseEnumNextEx( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out] */ LPLSLicenseEx lpLicense,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Abstract:

    Fetch next record match enumeration criterial.

Parameters:

    phContext : Client context handle.
    lpLicense : return next record that match enumeration criterial.
    dwErrCode : error code.

Returns:

    Function returns RPC status, dwErrCode return error code.

Note:

    Must have call TLSRpcLicenseEnumBegin().

++*/
{
    DWORD status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    InterlockedIncrement( &lpContext->m_RefCount );
    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcLicenseEnumNextEx\n"),
            lpContext->m_Client
        );

    if(lpContext->m_ContextType != CONTEXTHANDLE_LICENSE_ENUM_TYPE)
    {
        SetLastError(status=TLS_E_INVALID_SEQUENCE);
    }
    else
    {
        PTLSDbWorkSpace pDbWkSpace=(PTLSDbWorkSpace)lpContext->m_ContextHandle;
        try {
            LICENSEDCLIENT license;

            memset(lpLicense, 0, sizeof(LSLicenseEx));

            status=TLSDBLicenseEnumNext( 
                                pDbWkSpace, 
                                &license
                            );
            if(status == ERROR_SUCCESS)
            {
                ConvertLicenseToLSLicenseEx(&license, lpLicense);
            }
        } 
        catch( SE_Exception e ) {
            status = e.getSeNumber();
        }
        catch(...) {
            status = TLS_E_INTERNAL;
        }        
    }

    #if DBG
    lpContext->m_LastCall = RPC_CALL_LICENSEENUMNEXT;
    #endif
   
    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcLicenseEnumEnd( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

Abstract:

    Terminate a enumeration.

Parameters:

    phContext :
    dwErrCode :

Returns:


Note

++*/
{
    DWORD status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    InterlockedIncrement( &lpContext->m_RefCount );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcLicenseEnumEnd\n"),
            lpContext->m_Client
        );

    try {
        if(lpContext->m_ContextType != CONTEXTHANDLE_LICENSE_ENUM_TYPE)
        {
            SetLastError(status=ERROR_INVALID_HANDLE);
        }
        else
        {
            PTLSDbWorkSpace pDbWkSpace = (PTLSDbWorkSpace)lpContext->m_ContextHandle;

            TLSDBLicenseEnumEnd(pDbWkSpace);
            ReleaseWorkSpace(&pDbWkSpace);
            lpContext->m_ContextType = CONTEXTHANDLE_EMPTY_TYPE;
        }
    }
    catch(...) {
        status = TLS_E_INTERNAL;
    }        

    #if DBG
    lpContext->m_LastCall = RPC_CALL_LICENSEENUMEND;
    #endif

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcLicenseSetStatus( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwSetParam,
    /* [in] */ LPLSLicense lpLicense,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

++*/
{
    PTLSDbWorkSpace pDbWkSpace=NULL;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;
    InterlockedIncrement( &lpContext->m_RefCount );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcLicenseSetStatus\n"),
            lpContext->m_Client
        );

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_ADMIN))
    {
        status = TLS_E_ACCESS_DENIED;
    }
    else if(dwSetParam != LSLICENSE_EXSEARCH_LICENSESTATUS)
    {
        status = TLS_E_INVALID_DATA;
    }
    else
    {
        if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
        {
            status=TLS_E_ALLOCATE_HANDLE;
        }
        else
        {
            CLEANUPSTMT;

            BEGIN_TRANSACTION(pDbWkSpace);

            try {
                LICENSEDCLIENT license;

                ConvertLSLicenseToLicense(lpLicense, &license);
                status=TLSDBLicenseSetValue( 
                                    USEHANDLE(pDbWkSpace), 
                                    dwSetParam, 
                                    &license,
                                    FALSE 
                                );
            }
            catch(...) {
                status = TLS_E_INTERNAL;
            }

            if(TLS_ERROR(status))
            {
                ROLLBACK_TRANSACTION(pDbWkSpace);
            }
            else
            {
                COMMIT_TRANSACTION(pDbWkSpace);
            }

            FREEDBHANDLE(pDbWkSpace);
        }
    }

    #if DBG
    lpContext->m_LastCall = RPC_CALL_LICENSESETSTATUS;
    #endif

    lpContext->m_LastError = status;
    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetAvailableLicenses( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwSearchParm,
    /* [ref][in] */ LPLSKeyPack lplsKeyPack,
    /* [ref][out] */ LPDWORD lpdwAvail,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

++*/
{
    PTLSDbWorkSpace pDbWkSpace=NULL;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetAvailableLicenses\n"),
            lpContext->m_Client
        );


    InterlockedIncrement( &lpContext->m_RefCount );

    //
    // Don't use global cached DB connection handle, it is possible
    // to get in-consistent value using other DB handle, however, it is
    // also possible that during the time that this function return and
    // the time that client actually make the call to allocate license,
    // all available licenses were allocated by other client.
    //
    pDbWkSpace = AllocateWorkSpace(g_GeneralDbTimeout);
    if(pDbWkSpace == NULL)
    {
        status=TLS_E_ALLOCATE_HANDLE;
    }
    else
    {
        try {
            LICENSEPACK keypack;

            memset(&keypack, 0, sizeof(keypack));

            ConvertLsKeyPackToKeyPack(
                            lplsKeyPack, 
                            &keypack, 
                            NULL
                        );

            status = TLSDBKeyPackGetAvailableLicenses(
                                            pDbWkSpace,
                                            dwSearchParm,
                                            &keypack,
                                            lpdwAvail
                                        );

            //FreeTlsLicensePack(&keypack);
        } 
        catch(...) {
            status = TLS_E_INTERNAL;    
        }

        ReleaseWorkSpace(&pDbWkSpace);
    }        
    
    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetRevokeKeyPackList( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [out][in] */ PDWORD pcbNumberOfRange,
    /* [size_is][out] */ LPLSRange __RPC_FAR *ppRevokeRange,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

++*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetRevokeLicenseList( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [out][in] */ PDWORD pcbNumberOfRange,
    /* [size_is][out] */ LPLSRange __RPC_FAR *ppRevokeRange,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

++*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcReturnKeyPack( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwKeyPackId,
    /* [in] */ DWORD dwReturnReason,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

++*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcReturnLicense( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwKeyPackId,
    /* [in] */ DWORD dwLicenseId,
    /* [in] */ DWORD dwReturnReason,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

++*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcInstallCertificate( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwCertType,
    /* [in] */ DWORD dwCertLevel,
    /* [in] */ DWORD cbSignCert,
    /* [size_is][in] */ PBYTE pbSignCert,
    /* [in] */ DWORD cbExchCert,
    /* [size_is][in] */ PBYTE pbExchCert,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcInstallCertificate\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    DWORD cbLsSignCert=0;
    PBYTE pbLsSignCert=NULL;

    DWORD cbLsExchCert=0;
    PBYTE pbLsExchCert=NULL;

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_ADMIN))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    if(pbSignCert == NULL || pbExchCert == NULL)
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;

    }

#if DBG
    //
    // Verify input data
    //
    status = TLSVerifyCertChainInMomory(
                                g_hCryptProv,
                                pbSignCert,
                                cbSignCert
                            );
    if(status != ERROR_SUCCESS)
    {
        status = TLS_E_INVALID_DATA;
    }

    //
    // Verify input data
    //
    status = TLSVerifyCertChainInMomory(
                                g_hCryptProv,
                                pbExchCert,
                                cbExchCert
                            );
    if(status != ERROR_SUCCESS)
    {
        status = TLS_E_INVALID_DATA;
    }
#endif

    //
    // Block RPC call to serialize install certificate
    //
    if(AcquireRPCExclusiveLock(INFINITE) == FALSE)
    {
        status=TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    if(AcquireAdministrativeLock(INFINITE) == TRUE)
    {
        try {
            if(dwCertLevel == 0)
            {
                status = TLSSaveRootCertificatesToStore(
                                               g_hCryptProv,
                                               cbSignCert, 
                                               pbSignCert, 
                                               cbExchCert,
                                               pbExchCert
                                            );
            }
            else
            {
                status = TLSSaveCertificatesToStore(
                                                g_hCryptProv, 
                                                dwCertType, 
                                                dwCertLevel, 
                                                cbSignCert, 
                                                pbSignCert, 
                                                cbExchCert,
                                                pbExchCert
                                            );

                if(status == ERROR_SUCCESS && dwCertType == CERTIFICATE_CA_TYPE)
                {
                    if(cbSignCert)
                    {
                        status = IsCertificateLicenseServerCertificate(
                                                            g_hCryptProv,
                                                            AT_SIGNATURE,
                                                            cbSignCert,
                                                            pbSignCert,
                                                            &cbLsSignCert,
                                                            &pbLsSignCert
                                                        );
                    }

                    if(status == ERROR_SUCCESS && cbExchCert)
                    {
                        status = IsCertificateLicenseServerCertificate(
                                                            g_hCryptProv,
                                                            AT_KEYEXCHANGE,
                                                            cbExchCert,
                                                            pbExchCert,
                                                            &cbLsExchCert,
                                                            &pbLsExchCert
                                                        );

                    }

                    //
                    // Install what we have here.
                    //
                    if(status == ERROR_SUCCESS && (cbLsExchCert || pbLsExchCert))
                    {
                        status = TLSInstallLsCertificate(
                                                    cbLsSignCert, 
                                                    pbLsSignCert, 
                                                    cbLsExchCert, 
                                                    pbLsExchCert
                                                );
                    }

                    #ifdef ENFORCE_LICENSING

                    // enforce version, check what's installed and restore backup if necessary
                    // non-enforce, just install, we won't use it anyway.
                    if(status == ERROR_SUCCESS && (cbLsExchCert || pbLsExchCert))
                    {
                        // reload certificate
                        if(TLSLoadVerifyLicenseServerCertificates() != ERROR_SUCCESS)
                        {
                            status = TLS_E_INVALID_DATA;

                            // delete the primary certificate registry key
                            TLSRegDeleteKey(
                                        HKEY_LOCAL_MACHINE,
                                        LSERVER_SERVER_CERTIFICATE_REGKEY
                                    );

                            //
                            // reload certificate, if anything goes wrong, we will goes 
                            // back to unregister mode.
                            //
                            if(TLSLoadServerCertificate() == FALSE)
                            {
                                // critical error occurred
                                TLSLogErrorEvent(TLS_E_LOAD_CERTIFICATE);
                                
                                // initiate self-shutdown
                                GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
                            }
                        }
                        else
                        {
                            DWORD dwStatus;

                            // make sure our backup is up to date.
                            dwStatus = TLSRestoreLicenseServerCertificate(
                                                                LSERVER_SERVER_CERTIFICATE_REGKEY,
                                                                LSERVER_SERVER_CERTIFICATE_REGKEY_BACKUP1
                                                            );
                            if(dwStatus != ERROR_SUCCESS)
                            {
                                TLSLogWarningEvent(TLS_W_BACKUPCERTIFICATE);

                                TLSRegDeleteKey(
                                        HKEY_LOCAL_MACHINE,
                                        LSERVER_SERVER_CERTIFICATE_REGKEY_BACKUP1
                                    );
                            }
                                    
                            dwStatus = TLSRestoreLicenseServerCertificate(
                                                                LSERVER_SERVER_CERTIFICATE_REGKEY,
                                                                LSERVER_SERVER_CERTIFICATE_REGKEY_BACKUP2
                                                            );
                            if(dwStatus != ERROR_SUCCESS)
                            {
                                TLSLogWarningEvent(TLS_W_BACKUPCERTIFICATE);

                                TLSRegDeleteKey(
                                        HKEY_LOCAL_MACHINE,
                                        LSERVER_SERVER_CERTIFICATE_REGKEY_BACKUP2
                                    );
                            }
                        }
                    }
                    #endif

                    if(pbLsSignCert)
                    {
                        FreeMemory(pbLsSignCert);
                    }

                    if(pbLsExchCert)
                    {
                        FreeMemory(pbLsExchCert);
                    }
                }
            }
        }
        catch( SE_Exception e ) {
            status = e.getSeNumber();
        }
        catch(...) {
            status = TLS_E_INTERNAL;
        }

        ReleaseAdministrativeLock();
    }
    else
    {
        status=TLS_E_ALLOCATE_HANDLE;
    }

    ReleaseRPCExclusiveLock();

cleanup:

    lpContext->m_LastError=status;

    #if DBG
    lpContext->m_LastCall = RPC_CALL_INSTALL_SERV_CERT;
    #endif

    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);
    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
error_status_t 
TLSRpcGetServerCertificate( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ BOOL bSignCert,
    /* [size_is][size_is][out] */ LPBYTE __RPC_FAR *ppCertBlob,
    /* [ref][out] */ LPDWORD lpdwCertBlobLen,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;
    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    InterlockedIncrement( &lpContext->m_RefCount );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetServerCertificate\n"),
            lpContext->m_Client
        );

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_ADMIN))
    {
        status = TLS_E_ACCESS_DENIED;
    }
    else if(!g_pbExchangeEncodedCert || !g_cbExchangeEncodedCert ||
            !g_pbSignatureEncodedCert || !g_cbSignatureEncodedCert)
    {
        status = TLS_E_NO_CERTIFICATE;
    }
    else 
    {
        if(AcquireAdministrativeLock(INFINITE) == TRUE)
        {
            try{
                status = TLSSaveCertAsPKCS7( 
                                        (bSignCert) ? g_pbSignatureEncodedCert : g_pbExchangeEncodedCert,
                                        (bSignCert) ? g_cbSignatureEncodedCert : g_cbExchangeEncodedCert,
                                        ppCertBlob,
                                        lpdwCertBlobLen
                                    );

                // hack so that we can continue testing...
                if(g_bHasHydraCert == FALSE)
                {
                    if(g_pbServerSPK != NULL && g_cbServerSPK != 0)
                    {
                        status = TLS_W_SELFSIGN_CERTIFICATE;
                    }
                    else
                    {
                        status = TLS_W_TEMP_SELFSIGN_CERT;
                    }
                }
            }
            catch( SE_Exception e ) {
                status = e.getSeNumber();
            }
            catch(...)
            {
                status = TLS_E_INTERNAL;
            }

            ReleaseAdministrativeLock();
        }
        else
        {
            status = TLS_E_ALLOCATE_HANDLE;
        }
    }

    lpContext->m_LastError=status;

    #if DBG
    lpContext->m_LastCall = RPC_CALL_GETSERV_CERT;
    #endif

    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);
    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

//-------------------------------------------------------------------------------
void
MyFreeLicenseKeyPack(
    PLicense_KeyPack pLicenseKeyPack 
    )
/*
*/
{
    DWORD i;

    PKeyPack_Description pKpDesc;

    if( pLicenseKeyPack->pDescription )
    {
        for( i = 0, pKpDesc = pLicenseKeyPack->pDescription;
             i < pLicenseKeyPack->dwDescriptionCount;
             i++, pKpDesc++ )
        {
            if(pKpDesc->pDescription)
                LocalFree( pKpDesc->pDescription );

            if(pKpDesc->pbProductName)
                LocalFree( pKpDesc->pbProductName );
        }
    }

    if(pLicenseKeyPack->pDescription)
        LocalFree( pLicenseKeyPack->pDescription );

    if(pLicenseKeyPack->pbManufacturer && pLicenseKeyPack->cbManufacturer != 0)
        LocalFree( pLicenseKeyPack->pbManufacturer );

    if(pLicenseKeyPack->pbManufacturerData && pLicenseKeyPack->cbManufacturerData != 0)
        LocalFree( pLicenseKeyPack->pbManufacturerData );

    if(pLicenseKeyPack->pbProductId && pLicenseKeyPack->cbProductId != 0)
        LocalFree( pLicenseKeyPack->pbProductId );
    return;
}

//---------------------------------------------------------------------
error_status_t 
TLSRpcRegisterLicenseKeyPack( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [size_is][in] */ LPBYTE pbCHCertBlob,
    /* [in] */ DWORD cbCHCertBlobSize,
    /* [size_is][in] */ LPBYTE pbRootCertBlob,
    /* [in] */ DWORD cbRootCertBlob,
    /* [size_is][in] */ LPBYTE lpKeyPackBlob,
    /* [in] */ DWORD dwKeyPackBlobLen,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*++

++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;
    LSKeyPack keypack;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );


    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcRegisterLicenseKeyPack\n"),
            lpContext->m_Client
        );

    PTLSDbWorkSpace pDbWkSpace;

    InterlockedIncrement( &lpContext->m_RefCount );
    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_ADMIN))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }


    if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
    {
        status=TLS_E_ALLOCATE_HANDLE;
    }
    else
    {
        License_KeyPack pLicenseKeyPack;
        LicensePackDecodeParm LkpDecodeParm;

        memset(
                &LkpDecodeParm,
                0,
                sizeof(LicensePackDecodeParm)
            );

        LkpDecodeParm.hCryptProv = g_hCryptProv;
        LkpDecodeParm.pbDecryptParm = (PBYTE)g_pszServerPid;
        LkpDecodeParm.cbDecryptParm = (lstrlen(g_pszServerPid) * sizeof(TCHAR));
        LkpDecodeParm.cbClearingHouseCert = cbCHCertBlobSize;
        LkpDecodeParm.pbClearingHouseCert = pbCHCertBlob;
        LkpDecodeParm.pbRootCertificate = pbRootCertBlob;
        LkpDecodeParm.cbRootCertificate = cbRootCertBlob;

        //
        // make code clean, always start a transaction
        //
        CLEANUPSTMT;
        BEGIN_TRANSACTION(pDbWkSpace);

        try {
            status = DecodeLicenseKeyPackEx(
                                    &pLicenseKeyPack,
                                    &LkpDecodeParm,
                                    dwKeyPackBlobLen,
                                    lpKeyPackBlob
                                );

            if(status != LICENSE_STATUS_OK)
            {
                status = TLS_E_DECODE_KEYPACKBLOB;
                DBGPrintf(
                        DBG_INFORMATION,
                        DBG_FACILITY_RPC,
                        DBGLEVEL_FUNCTION_DETAILSIMPLE,
                        _TEXT("Can't decode key pack blob - %d...\n"),
                        status);
            }
            else
            {
                status=TLSDBRegisterLicenseKeyPack(
                                    USEHANDLE(pDbWkSpace), 
                                    &pLicenseKeyPack,
                                    &keypack
                                );

                MyFreeLicenseKeyPack(&pLicenseKeyPack);
            }
        }
        catch( SE_Exception e ) {
            status = e.getSeNumber();
        }
        catch(...) {
            status = TLS_E_INTERNAL;
        }

        if(TLS_ERROR(status)) 
        {
            ROLLBACK_TRANSACTION(pDbWkSpace);
        }
        else
        {
            COMMIT_TRANSACTION(pDbWkSpace);
        }

        FREEDBHANDLE(pDbWkSpace);
    }

    //
    // Post a sync work object
    //
    if(status == ERROR_SUCCESS)
    {
        if(TLSAnnounceLKPToAllRemoteServer(
                                        keypack.dwKeyPackId,
                                        0
                                    ) != ERROR_SUCCESS)
        {
            TLSLogWarningEvent(TLS_W_ANNOUNCELKP_FAILED);
        }
    }

cleanup:

    lpContext->m_LastError=status;

    #if DBG
    lpContext->m_LastCall = RPC_CALL_REGISTER_LICENSE_PACK;
    #endif

    InterlockedDecrement( &lpContext->m_RefCount );
    *dwErrCode = TLSMapReturnCode(status);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////
error_status_t 
TLSRpcRequestTermServCert(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ LPTLSHYDRACERTREQUEST pRequest,
    /* [ref][out][in] */ PDWORD pcbChallengeData,
    /* [size_is][out] */ PBYTE* ppbChallengeData,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Abstract:

    Private routine to issue certificate to Terminal Server.

Parameter:

    phContext : Client context handle.
    pRequest : Terminal Server specific certificate request.
    pcbChallengeData : size of Server randomly generated challenge data 
                       to Terminal Server.
    ppbChallengeData : Server randomly generated challenge data to Terminal
                       server.

    pdwErrCode : Error code.

Returns:

    Function always return RPC_S_OK, actual error code is returned in
    pdwErrCode.

Note:

    Routine does not actually issue a license to Terminal Server, Terminal
    Server must call TLSRpcRetrieveTermServCert() to retrieve its own 
    license.

--*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;
    LPTERMSERVCERTREQHANDLE lpHandle=NULL;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcRequestTermServCert\n"),
            lpContext->m_Client
        );

    *ppbChallengeData = NULL;
    *pcbChallengeData = 0;

    // verify client handle 
    InterlockedIncrement( &lpContext->m_RefCount );
    if(lpContext->m_ContextType != CONTEXTHANDLE_EMPTY_TYPE)
    {
        SetLastError(status=TLS_E_INVALID_SEQUENCE);
        goto cleanup;
    }

    lpHandle = (LPTERMSERVCERTREQHANDLE)AllocateMemory(
                                                sizeof(TERMSERVCERTREQHANDLE)
                                            );
    if(lpHandle == NULL)
    {
        SetLastError(status = ERROR_OUTOFMEMORY);
        goto cleanup;
    }

    //
    // Generate Challenge Data
    //
    lpHandle->pCertRequest = pRequest;
    status = TLSGenerateChallengeData( 
                        CLIENT_INFO_HYDRA_SERVER,
                        &lpHandle->cbChallengeData,
                        &lpHandle->pbChallengeData
                    );

    if(status != ERROR_SUCCESS)
    {
        goto cleanup;
    }

    // return challenge data
    *pcbChallengeData = lpHandle->cbChallengeData;
    *ppbChallengeData = (PBYTE)midl_user_allocate(*pcbChallengeData);
    if(*ppbChallengeData == NULL)
    {
        SetLastError(status = ERROR_OUTOFMEMORY);
        goto cleanup;
    }

    memcpy( *ppbChallengeData,
            lpHandle->pbChallengeData,
            lpHandle->cbChallengeData);

    lpContext->m_ContextHandle = (HANDLE)lpHandle;
    lpContext->m_ContextType = CONTEXTHANDLE_HYDRA_REQUESTCERT_TYPE;

cleanup:

    if(status != ERROR_SUCCESS)
    {
        // frees up memory.
        // Can't overwrite context type.
        //lpContext->m_ContextType = CONTEXTHANDLE_EMPTY_TYPE;

        if(lpHandle != NULL)
        {
            FreeMemory(lpHandle->pbChallengeData);
            FreeMemory(lpHandle);
        }

        if(*ppbChallengeData != NULL)
        {
            midl_user_free(*ppbChallengeData);
        }

        if(pRequest != NULL)
        {
            midl_user_free(pRequest);
        }

        *ppbChallengeData = NULL;
        *pcbChallengeData = 0;
    }

    InterlockedDecrement( &lpContext->m_RefCount );
    lpContext->m_LastError=status;

    #if DBG
    lpContext->m_LastCall = RPC_CALL_REQUEST_TERMSRV_CERT;
    #endif

    *pdwErrCode = TLSMapReturnCode(status);

    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////
error_status_t 
TLSRpcRetrieveTermServCert(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD cbResponseData,
    /* [size_is][in] */ PBYTE pbResponseData,
    /* [ref][out][in] */ PDWORD pcbCert,
    /* [size_is][out] */ PBYTE* ppbCert,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Abstract:

    Private routine to retrieve Terminal Server's license.

Parameters:

    phContext : client context handle.
    cbResponseData : size of Terminal Server responses data to 
                     license server's challenge.
    pbResponseData : Terminal Server responses data to license 
                     server's challenge.
    pcbCert : Size of Terminal Server's license in bytes.
    ppbCert : Terminal Server's license.
    pdwErrCode : error code if fail.

Returns:

    Function returns RPC_S_OK, actual error code returns in
    pdwErrCode.

Note:

    Must have call TLSRpcRequestTermServCert().


--*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;
    LPTERMSERVCERTREQHANDLE lpHandle=NULL;
    CTLSPolicy* pPolicy=NULL;
    PMHANDLE hClient;

    PBYTE pbPkcs7=NULL;
    DWORD cbPkcs7=0;
    TLSDBLICENSEREQUEST LicenseRequest;
    DWORD dwQuantity = 1;
    TLSPRODUCTINFO ProductInfo;

    TCHAR szCompanyName[LSERVER_MAX_STRING_SIZE];
    TCHAR szMachineName[MAXCOMPUTERNAMELENGTH];
    TCHAR szUserName[MAXUSERNAMELENGTH];

    PTLSDbWorkSpace pDbWkSpace;

    PMLICENSEREQUEST PMLicenseRequest;
    PPMLICENSEREQUEST pAdjustedRequest;

    TLSDBLICENSEDPRODUCT LicensedProduct;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

	

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcRetrieveTermServCert\n"),
            lpContext->m_Client
        );


    // verify client handle 
    InterlockedIncrement( &lpContext->m_RefCount );
    if(lpContext->m_ContextType != CONTEXTHANDLE_HYDRA_REQUESTCERT_TYPE)
    {
        SetLastError(status = TLS_E_INVALID_SEQUENCE);
        goto cleanup;
    }

    lpHandle = (LPTERMSERVCERTREQHANDLE)lpContext->m_ContextHandle;
    if( lpHandle == NULL || lpHandle->pCertRequest == NULL ||
        lpHandle->pCertRequest->pbEncryptedHwid == NULL ||
        lpHandle->pCertRequest->cbEncryptedHwid == 0 )
    {
        SetLastError(status = TLS_E_INVALID_SEQUENCE);
        goto cleanup;
    }

	
    //
    // Verify challenge response data
    //

    
    //
    // Request a license from specific key pack
    //

    memset(&LicenseRequest, 0, sizeof(TLSDBLICENSEREQUEST));

    if(!LoadResourceString(
                IDS_HS_COMPANYNAME,
                szCompanyName,
                sizeof(szCompanyName) / sizeof(szCompanyName[0])))
    {
        SetLastError(status = TLS_E_INTERNAL);
        goto cleanup;
    }    

    if(lpContext->m_Client == NULL)
    {
        if(!LoadResourceString(
                    IDS_HS_MACHINENAME,
                    LicenseRequest.szMachineName,
                    sizeof(LicenseRequest.szMachineName)/sizeof(LicenseRequest.szMachineName[0])))
        {
            SetLastError(status = TLS_E_INTERNAL);
            goto cleanup;
        }

        if(!LoadResourceString(
                    IDS_HS_USERNAME,
                    LicenseRequest.szUserName,
                    sizeof(LicenseRequest.szUserName)/sizeof(LicenseRequest.szUserName[0])))
        {
            SetLastError(status = TLS_E_INTERNAL);
            goto cleanup;
        }
    }
    else
    {
        SAFESTRCPY(LicenseRequest.szMachineName, lpContext->m_Client);
        SAFESTRCPY(LicenseRequest.szUserName, lpContext->m_Client);
    }

    LicenseRequest.dwProductVersion = HYDRACERT_PRODUCT_VERSION;
    LicenseRequest.pszProductId = HYDRAPRODUCT_HS_CERTIFICATE_SKU;
    LicenseRequest.pszCompanyName = szCompanyName;

    LicenseRequest.dwLanguageID = GetSystemDefaultLangID(); // ignore
    LicenseRequest.dwPlatformID = CLIENT_PLATFORMID_WINDOWS_NT_FREE; // WINDOWS
    LicenseRequest.pbEncryptedHwid = lpHandle->pCertRequest->pbEncryptedHwid;
    LicenseRequest.cbEncryptedHwid = lpHandle->pCertRequest->cbEncryptedHwid;

    status=LicenseDecryptHwid(
                        &LicenseRequest.hWid, 
                        LicenseRequest.cbEncryptedHwid,
                        LicenseRequest.pbEncryptedHwid,
                        g_cbSecretKey,
                        g_pbSecretKey
                    );

    if(status != ERROR_SUCCESS)
    {
        status = ERROR_INVALID_PARAMETER;
        goto cleanup;
    }

    LicenseRequest.pClientPublicKey = (PCERT_PUBLIC_KEY_INFO)lpHandle->pCertRequest->pSubjectPublicKeyInfo;
    LicenseRequest.clientCertRdn.type =  LSCERT_RDN_STRING_TYPE;
    LicenseRequest.clientCertRdn.szRdn = lpHandle->pCertRequest->szSubjectRdn;
    LicenseRequest.dwNumExtensions = lpHandle->pCertRequest->dwNumCertExtension;
    LicenseRequest.pExtensions = (PCERT_EXTENSION)lpHandle->pCertRequest->pCertExtensions;

    hClient = GenerateClientId();
    pPolicy = AcquirePolicyModule(NULL, NULL, FALSE);
    if(pPolicy == NULL)
    {
        SetLastError(status = TLS_E_INTERNAL);
        goto cleanup;
    }

    PMLicenseRequest.dwProductVersion = LicenseRequest.dwProductVersion;
    PMLicenseRequest.pszProductId = LicenseRequest.pszProductId;
    PMLicenseRequest.pszCompanyName = LicenseRequest.pszCompanyName;
    PMLicenseRequest.dwLanguageId = LicenseRequest.dwLanguageID;
    PMLicenseRequest.dwPlatformId = LicenseRequest.dwPlatformID;
    PMLicenseRequest.pszMachineName = LicenseRequest.szMachineName;
    PMLicenseRequest.pszUserName = LicenseRequest.szUserName;
    PMLicenseRequest.dwLicenseType = LICENSETYPE_LICENSE;

    //
    // Inform Policy module start of new license request
    //
    status = pPolicy->PMLicenseRequest(
                                hClient,
                                REQUEST_NEW,
                                (PVOID) &PMLicenseRequest,
                                (PVOID *) &pAdjustedRequest
                            );

    if(status != ERROR_SUCCESS)
    {
        goto cleanup;
    }
    
    LicenseRequest.pPolicy = pPolicy;
    LicenseRequest.hClient = hClient;

    LicenseRequest.pPolicyLicenseRequest = pAdjustedRequest;
    LicenseRequest.pClientLicenseRequest = &PMLicenseRequest;


    // Call issue new license from sepcific keypack
    if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
    {
        status = TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    CLEANUPSTMT;
    BEGIN_TRANSACTION(pDbWkSpace);

    try {
        status = TLSDBIssuePermanentLicense( 
                                    USEHANDLE(pDbWkSpace),
                                    &LicenseRequest,
                                    FALSE,      // bLatestVersion
                                    FALSE,      // bAcceptFewerLicenses
                                    &dwQuantity,
                                    &LicensedProduct,
                                    0
                                );
    } 
    catch( SE_Exception e ) {
        status = e.getSeNumber();
    }
    catch(...) {
        status = TLS_E_INTERNAL;
    }
    
    if(TLS_ERROR(status))
    {
        ROLLBACK_TRANSACTION(pDbWkSpace);
    }
    else
    {
        COMMIT_TRANSACTION(pDbWkSpace);
    }

    FREEDBHANDLE(pDbWkSpace);

    if(status == ERROR_SUCCESS)
    {
        LicensedProduct.pSubjectPublicKeyInfo = (PCERT_PUBLIC_KEY_INFO)lpHandle->pCertRequest->pSubjectPublicKeyInfo;

        //
        // Generate client certificate
        //
        status = TLSGenerateClientCertificate(
                                    g_hCryptProv,
                                    1,
                                    &LicensedProduct,
                                    LICENSE_DETAIL_DETAIL,
                                    &pbPkcs7,
                                    &cbPkcs7
                                );

        if(TLS_ERROR(status) == TRUE)
        {
            goto cleanup;
        }

        status = TLSChainProprietyCertificate(
                                    g_hCryptProv,
                                    (CanIssuePermLicense() == FALSE),
                                    pbPkcs7, 
                                    cbPkcs7, 
                                    ppbCert,
                                    pcbCert 
                                );

        if(status == ERROR_SUCCESS)
        {
            if(CanIssuePermLicense() == FALSE) 
            {
                status = TLS_W_SELFSIGN_CERTIFICATE;
            }
        }
    }

cleanup:

    FreeMemory(pbPkcs7);

    if(pPolicy)
    {
        ReleasePolicyModule(pPolicy);   
    }


    //
    // Free up Hydra Certificate Request handle, 
    // all_nodes attribute so single free.
    //
    if(lpHandle)
    {
        if(lpHandle->pCertRequest)
        {
            midl_user_free(lpHandle->pCertRequest);
        }
    
        if(lpHandle->pbChallengeData)
        {
            midl_user_free(lpHandle->pbChallengeData);
        }

        FreeMemory(lpHandle);
    }

    if(lpContext->m_ContextType == CONTEXTHANDLE_HYDRA_REQUESTCERT_TYPE)
    {
        //
        // force calling TLSRpcRequestTermServCert() again
        //
        lpContext->m_ContextType = CONTEXTHANDLE_EMPTY_TYPE;
        lpContext->m_ContextHandle = NULL;
    }

    InterlockedDecrement( &lpContext->m_RefCount );

    lpContext->m_LastError=status;

    #if DBG
    lpContext->m_LastCall = RPC_CALL_RETRIEVE_TERMSRV_CERT;
    #endif

    *pdwErrCode = TLSMapReturnCode(status);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////
error_status_t 
TLSRpcAuditLicenseKeyPack(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwKeyPackId,
    /* [in] */ FILETIME ftStartTime,
    /* [in] */ FILETIME ftEndTime,
    /* [in] */ BOOL bResetCounter,
    /* [ref][out][in] */ LPTLSKeyPackAudit lplsAudit,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

    Not implemented yet!.

--*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcGetLSPKCS10CertRequest(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwCertType,
    /* [ref][out][in] */ PDWORD pcbData,
    /* [size_is][size_is][out] */ PBYTE __RPC_FAR *ppbData,
    /* [ref][out][in] */ PDWORD dwErrCode
    )
/*

Abstract:


Note:

    Only return our key at this time, not a PKCS10 request

*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetLSPKCS10CertRequest\n"),
            lpContext->m_Client
        );


    InterlockedIncrement( &lpContext->m_RefCount );
    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_ADMIN))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    if(AcquireAdministrativeLock(INFINITE) == TRUE)
    {
        status = RetrieveKey(
                        (dwCertType == TLSCERT_TYPE_EXCHANGE) ? 
                                LSERVER_LSA_PRIVATEKEY_EXCHANGE :
                                LSERVER_LSA_PRIVATEKEY_SIGNATURE,
                        ppbData,
                        pcbData
                    );

        ReleaseAdministrativeLock();
    }
    else
    {
        status = TLS_E_ALLOCATE_HANDLE;
    }

cleanup:
    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_GETPKCS10CERT_REQUEST;
    #endif

    *dwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////// 
//
// Replication function
//
////////////////////////////////////////////////////////////////////////////
error_status_t 
TLSRpcBeginReplication( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [string][in] */ LPTSTR pszLsSetupId,
    /* [string][in] */ LPTSTR pszLsServerName,
    /* [in] */ DWORD cbDomainSid,
    /* [size_is][in] */ PBYTE pbDomainSid,
    /* [ref][out][in] */ FILETIME __RPC_FAR *pftLastBackupTime,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

++*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcEndReplication( 
    /* [in] */ PCONTEXT_HANDLE phContext
    )
/*++

++*/
{
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcReplicateRecord( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][in] */ PTLSReplRecord pReplRecord,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

++*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcTableEnumBegin( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwSearchParam,
    /* [ref][in] */ PTLSReplRecord pRecord,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

++*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcTableEnumNext( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [ref][out][in] */ PTLSReplRecord pRecord,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

++*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcTableEnumEnd( 
    /* [in] */ PCONTEXT_HANDLE phContext
    )
/*++

++*/
{
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcInstallPolicyModule(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [string][in] */ LPTSTR pszCompanyName,
    /* [string][in] */ LPTSTR pszProductId,
    /* [string][in] */ LPTSTR pszPolicyDllName,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

++*/
{
    *pdwErrCode = TLSMapReturnCode(TLS_E_NOTSUPPORTED);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcAnnounceServer( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwAnnounceType,
    /* [in] */ FILETIME __RPC_FAR *pLastStartupTime,
    /* [string][in] */ LPTSTR pszSetupId,
    /* [string][in] */ LPTSTR pszDomainName,
    /* [string][in] */ LPTSTR pszLserverName,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Abstract:

    Private routine for other license server to announce presence of
    itself.

Parameters:



Returns:


Note:


++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status = ERROR_SUCCESS;
    BOOL bSuccess = TRUE;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcAnnounceServer\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    __try {
        //
        // Verify it is a license server
        //
        if(lpContext->m_ClientFlags != CLIENT_ACCESS_LSERVER)
        {
            status = TLS_E_ACCESS_DENIED;
        }

        if( status == ERROR_SUCCESS && 
            (dwAnnounceType == TLSANNOUNCE_TYPE_STARTUP || dwAnnounceType == TLSANNOUNCE_TYPE_RESPONSE) )
        {      
            status = TLSRegisterServerWithName(
                                        pszSetupId, 
                                        pszDomainName, 
                                        pszLserverName
                                    );
            if(status == TLS_E_DUPLICATE_RECORD)
            {
                status = ERROR_SUCCESS;
            }
        }

        if(status == ERROR_SUCCESS)
        {
            if(dwAnnounceType == TLSANNOUNCE_TYPE_STARTUP)
            {
                //
                // Prevent loop back, use job to response announce
                //
                status = TLSStartAnnounceResponseJob(
                                                pszSetupId,
                                                pszDomainName,
                                                pszLserverName,
                                                &g_ftLastShutdownTime
                                            );
            }

            if(status == ERROR_SUCCESS)
            {
                // Create a CSSync workobject to sync. local LKP
                status = TLSPushSyncLocalLkpToServer(
                                    pszSetupId,
                                    pszDomainName,
                                    pszLserverName,
                                    pLastStartupTime
                                );
            }
            else
            {
                // reset error code, can't connect back to server -
                // server might be available anymore.
                status = ERROR_SUCCESS;
            }
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        status = GetExceptionCode();
    }

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_ANNOUNCE_SERVER;
    #endif

    *pdwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcLookupServer( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [string][in] */ LPTSTR pszLookupSetupId,
    /* [size_is][string][out][in] */ LPTSTR pszLsSetupId,
    /* [out][in] */ PDWORD pcbSetupId,
    /* [size_is][string][out][in] */ LPTSTR pszDomainName,
    /* [ref][out][in] */ PDWORD pcbDomainName,
    /* [size_is][string][out][in] */ LPTSTR pszMachineName,
    /* [ref][out][in] */ PDWORD pcbMachineName,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Abstract:

    Look up a license server via a license server's setupId.


Parameters:


Returns:


Note:


++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcLookupServer\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    TLServerInfo ServerInfo;
    DWORD dwStatus = ERROR_SUCCESS;

    __try {

        if(_tcsicmp(pszLookupSetupId, g_pszServerPid) == 0)
        {
            _tcsncpy(
                    pszLsSetupId,
                    g_pszServerPid,
                    min(_tcslen(g_pszServerPid), *pcbSetupId)
                );

            if(*pcbSetupId <= _tcslen(g_pszServerPid))
            {
                dwStatus = TLS_E_INVALID_DATA;
            }
            else
            {
                pszLsSetupId[min(_tcslen(g_pszServerPid), *pcbSetupId - 1)] = _TEXT('\0');
            }
            *pcbSetupId = _tcslen(g_pszServerPid) + 1;

            //--------------------------------------------------------------
            _tcsncpy(
                    pszDomainName, 
                    g_szScope,
                    min(_tcslen(g_szScope), *pcbDomainName)
                );

            if(*pcbDomainName <= _tcslen(g_szScope))
            {
                dwStatus = TLS_E_INVALID_DATA;
            }
            else
            {
                pszDomainName[min(_tcslen(g_szScope), *pcbDomainName - 1)] = _TEXT('\0');
            }
            *pcbDomainName = _tcslen(g_szScope) + 1;

            //--------------------------------------------------------------
            _tcsncpy(
                    pszMachineName,
                    g_szComputerName,
                    min(_tcslen(g_szComputerName), *pcbMachineName)
                );

            if(*pcbMachineName <= _tcslen(g_szComputerName))
            {
                dwStatus = TLS_E_INVALID_DATA;
            }
            else
            {
                pszMachineName[min(_tcslen(g_szComputerName), *pcbMachineName - 1)] = _TEXT('\0');
            }
            *pcbMachineName = _tcslen(g_szComputerName) + 1;

        }
        else
        {
            dwStatus = TLSLookupRegisteredServer(
                                        pszLookupSetupId,
                                        NULL,
                                        pszMachineName,
                                        &ServerInfo
                                    );
            if(dwStatus == ERROR_SUCCESS)
            {
                _tcsncpy(
                        pszLsSetupId, 
                        ServerInfo.GetServerId(),
                        min(_tcslen(ServerInfo.GetServerId()), *pcbSetupId)
                    );

                if(*pcbSetupId <= _tcslen(ServerInfo.GetServerId()))
                {
                    dwStatus = TLS_E_INVALID_DATA;
                }
                else
                {
                    pszLsSetupId[min(_tcslen(ServerInfo.GetServerId()), *pcbSetupId - 1)] = _TEXT('\0');
                }

                *pcbSetupId = _tcslen(ServerInfo.GetServerId()) + 1;

                //--------------------------------------------------------------
                _tcsncpy(
                        pszDomainName, 
                        ServerInfo.GetServerDomain(),
                        min(_tcslen(ServerInfo.GetServerDomain()), *pcbDomainName)
                    );
                if(*pcbDomainName <= _tcslen(ServerInfo.GetServerDomain()))
                {
                    dwStatus = TLS_E_INVALID_DATA;
                }
                else
                {
                    pszDomainName[min(_tcslen(ServerInfo.GetServerDomain()), *pcbDomainName - 1)] = _TEXT('\0');
                }
                *pcbDomainName = _tcslen(ServerInfo.GetServerDomain()) + 1;

                //--------------------------------------------------------------
                _tcsncpy(
                        pszMachineName,
                        ServerInfo.GetServerName(),
                        min(_tcslen(ServerInfo.GetServerName()), *pcbMachineName)
                    );

                if(*pcbMachineName <= _tcslen(ServerInfo.GetServerName()))
                {
                    dwStatus = TLS_E_INVALID_DATA;
                }
                else
                {
                    pszMachineName[min(_tcslen(ServerInfo.GetServerName()), *pcbMachineName - 1)] = _TEXT('\0');
                }
                *pcbMachineName = _tcslen(ServerInfo.GetServerName()) + 1;
            } 
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        dwStatus = GetExceptionCode();
    }

    lpContext->m_LastError=dwStatus;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_SERVERLOOKUP;
    #endif

    *pdwErrCode = TLSMapReturnCode(dwStatus);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcAnnounceLicensePack( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ PTLSReplRecord pReplRecord,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Abstract:

    Private routine for one license server to announce it has particular
    License Pack.

Parameters:



Returns:


++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD dwStatus=ERROR_SUCCESS;
    PTLSDbWorkSpace pDbWkSpace=NULL;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );


    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcAnnounceLicensePack\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    if(lpContext->m_ClientFlags != CLIENT_ACCESS_LSERVER)
    {
        dwStatus = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    if(pReplRecord->dwUnionType != UNION_TYPE_LICENSEPACK)
    {
        dwStatus = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
    {
        dwStatus = TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    CLEANUPSTMT;
    BEGIN_TRANSACTION(pDbWkSpace);

    try {
        TLSLICENSEPACK LicPack;
        LicPack = pReplRecord->w.ReplLicPack;
        //
        // TODO - verify input parameters
        //
        dwStatus = TLSDBRemoteKeyPackAdd(
                                USEHANDLE(pDbWkSpace),
                                &LicPack
                            );
    }
    catch( SE_Exception e ) {
        dwStatus = e.getSeNumber();
    }
    catch(...) {
        dwStatus = TLS_E_INTERNAL;
    }

    if(TLS_ERROR(dwStatus) && dwStatus != TLS_E_DUPLICATE_RECORD)
    {
        ROLLBACK_TRANSACTION(pDbWkSpace);
    }
    else
    {
        COMMIT_TRANSACTION(pDbWkSpace);
    }

    FREEDBHANDLE(pDbWkSpace);
    
cleanup:

    lpContext->m_LastError=dwStatus;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_ANNOUNCELICENSEPACK;
    #endif

    *pdwErrCode = TLSMapReturnCode(dwStatus);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcReturnLicensedProduct( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ PTLSLicenseToBeReturn pClientLicense,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++


++*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD dwStatus=ERROR_SUCCESS;
    CTLSPolicy* pPolicy=NULL;
    PTLSDbWorkSpace pDbWorkSpace;
    PMHANDLE hClient;
   
    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcReturnLicensedProduct\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    if(lpContext->m_ClientFlags != CLIENT_ACCESS_LSERVER)
    {
        dwStatus = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }


    pPolicy = AcquirePolicyModule(
                            pClientLicense->pszCompanyName,
                            pClientLicense->pszOrgProductId,
                            FALSE
                        );

    if(pPolicy == NULL)
    {
        dwStatus = GetLastError();
        goto cleanup;
    }

    hClient = GenerateClientId();

    if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
    {
        dwStatus=TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    CLEANUPSTMT;
    BEGIN_TRANSACTION(pDbWorkSpace);

    try {
        dwStatus = TLSReturnClientLicensedProduct(
                                        USEHANDLE(pDbWkSpace),
                                        hClient,
                                        pPolicy,
                                        pClientLicense
                                    );
    } 
    catch( SE_Exception e ) {
        dwStatus = e.getSeNumber();
    }
    catch(...) {
        SetLastError(dwStatus = TLS_E_INTERNAL);
    }
    
    if(TLS_ERROR(dwStatus))
    {
        ROLLBACK_TRANSACTION(pDbWorkSpace);
    }
    else
    {
        COMMIT_TRANSACTION(pDbWorkSpace);
    }

    FREEDBHANDLE(pDbWorkSpace);
            

cleanup:

    lpContext->m_LastError=dwStatus;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_RETURNLICENSE;
    #endif

    *pdwErrCode = TLSMapReturnCode(dwStatus);

    if(pPolicy)
    {
        pPolicy->PMLicenseRequest(
                            hClient,
                            REQUEST_COMPLETE,
                            UlongToPtr (dwStatus),
                            NULL
                        );
        
        ReleasePolicyModule(pPolicy);
    }

    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcChallengeServer(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwClientType,
    /* [in] */ PTLSCHALLENGEDATA pClientChallenge,
    /* [out][in] */ PTLSCHALLENGERESPONSEDATA* pServerResponse,
    /* [out][in] */ PTLSCHALLENGEDATA* pServerChallenge,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Abstract:

    Private routine for client to challenge server in order for client 
    confirm server's identity. License Server, in addition to response to 
    client's challenge, also generate random challenge data based on 
    client's self-declare type back to client.

Parameter:

    phContext : Client's context handle.
    dwClientType : Client self-pronounce type, valid values are ...
    pClientChallenge : Client challenge data.
    pServerResponse : Server's responses to client's challenge.
    pServerChallenge : Server's challenge to client.
    pdwErrCode : Error code if failed.

Returns:


Notes:

    Private routine for LrWiz and License Server to identify itself.

--*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;

    PTLSCHALLENGEDATA pChallenge=NULL;
    PTLSCHALLENGERESPONSEDATA pResponse = NULL;
    HCRYPTPROV hProv = NULL;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcChallengeServer\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    //if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_ADMIN))
    //{
    //    status = TLS_E_ACCESS_DENIED;
    //    goto cleanup;
    //}

    if(lpContext->m_ContextType != CONTEXTHANDLE_EMPTY_TYPE)
    {
        status = TLS_E_INVALID_SEQUENCE;
        goto cleanup;
    }

    //
    // Input parameters...
    //
    if( pClientChallenge == NULL || 
        pServerResponse == NULL ||
        pServerChallenge == NULL )
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    //
    // Verify Data send by client
    //
    if( pClientChallenge->dwVersion != TLS_CURRENT_CHALLENGE_VERSION ||
        pClientChallenge->cbChallengeData == 0 ||
        pClientChallenge->pbChallengeData == NULL )
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    pResponse = (PTLSCHALLENGERESPONSEDATA)midl_user_allocate(sizeof(TLSCHALLENGERESPONSEDATA));
    if(pResponse == NULL)
    {
        status = GetLastError();
        goto cleanup;
    }
                    
    pChallenge = (PTLSCHALLENGEDATA)AllocateMemory(sizeof(TLSCHALLENGEDATA));
    if(pChallenge == NULL)
    {
        status = GetLastError();
        goto cleanup;
    }

    *pServerChallenge = (PTLSCHALLENGEDATA)midl_user_allocate(sizeof(TLSCHALLENGEDATA));
    if(*pServerChallenge == NULL)
    {
        status = GetLastError();
        goto cleanup;
    }

    //
    // Generate Challenge response data
    //
    status = TLSGenerateChallengeResponseData(
                                        g_hCryptProv,
                                        dwClientType,
                                        pClientChallenge,
                                        &(pResponse->pbResponseData),
                                        &(pResponse->cbResponseData)
                                    );

    if(status != ERROR_SUCCESS)
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    //
    // Generate Server side challenge data
    //
    pChallenge->dwVersion = TLS_CURRENT_CHALLENGE_VERSION;

    if (CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT)) {
        if (!CryptGenRandom(hProv,sizeof(pChallenge->dwRandom), (BYTE *) &pChallenge->dwRandom)) {
            status = TLS_E_INTERNAL;
            goto cleanup;
        }
    } else {
        status = TLS_E_INTERNAL;
        goto cleanup;
    }

    //
    // This must range from 1 to 128, as it's used as an offset into the
    // challenge data buffer
    //

    pChallenge->dwRandom %= RANDOM_CHALLENGE_DATASIZE;
    pChallenge->dwRandom++;

    status = TLSGenerateRandomChallengeData(
                                        g_hCryptProv,
                                        &(pChallenge->pbChallengeData),
                                        &(pChallenge->cbChallengeData)
                                    );

    // base on type, mark this handle...
    if(dwClientType == CLIENT_TYPE_LRWIZ)
    {
        lpContext->m_ContextType = CONTEXTHANDLE_CHALLENGE_LRWIZ_TYPE;
    }
    else
    {
        lpContext->m_ContextType = CONTEXTHANDLE_CHALLENGE_SERVER_TYPE;
    }

    (*pServerChallenge)->pbChallengeData = (PBYTE)midl_user_allocate(pChallenge->cbChallengeData);
    if((*pServerChallenge)->pbChallengeData == NULL)
    {
        status = GetLastError();
        goto cleanup;
    }

    (*pServerChallenge)->dwVersion = TLS_CURRENT_CHALLENGE_VERSION;
    (*pServerChallenge)->dwRandom = pChallenge->dwRandom;
    (*pServerChallenge)->cbChallengeData = pChallenge->cbChallengeData;
    memcpy(
            (*pServerChallenge)->pbChallengeData,
            pChallenge->pbChallengeData,
            pChallenge->cbChallengeData
        );

    lpContext->m_ContextHandle = (HANDLE)(pChallenge);
    *pServerResponse = pResponse;

cleanup:

    if(status != ERROR_SUCCESS)
    {
        if(pChallenge)
        {
            if(pChallenge->pbChallengeData)
            {
                FreeMemory(pChallenge->pbChallengeData);
            }
            
            if(pChallenge->pbReservedData)
            {
                FreeMemory(pChallenge->pbReservedData);
            }

            FreeMemory(pChallenge);
        }

        if(pResponse)
        {
            if(pResponse->pbResponseData)
            {
                FreeMemory(pResponse->pbResponseData);
            }

            if(pResponse->pbReservedData)
            {
                FreeMemory(pResponse->pbReservedData);
            }
            
            midl_user_free(pResponse);
        }
    }

    if (hProv)
        CryptReleaseContext(hProv,0);

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_CHALLENGESERVER;
    #endif

    *pdwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcResponseServerChallenge(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ PTLSCHALLENGERESPONSEDATA pClientResponse,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

Abstract:

    Client's responses to Server challenge returned TLSRpcChallengeServer(),
    must have call TLSRpcChallengeServer().

Parameter:

    phContext:
    pClientResponses: Client's response to server's challenge.
    pdwErrCode : Return error code.


Returns:


Note:

--*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;
    DWORD dwClientType;
    PTLSCHALLENGEDATA pServerToClientChallenge;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcResponseServerChallenge\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    //if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_ADMIN))
    //{
    //    status = TLS_E_ACCESS_DENIED;
    //    goto cleanup;
    //}

    if( pClientResponse == NULL ||
        pClientResponse->pbResponseData == NULL || 
        pClientResponse->cbResponseData == 0 )
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    if(lpContext->m_ContextType != CONTEXTHANDLE_CHALLENGE_SERVER_TYPE &&
       lpContext->m_ContextType != CONTEXTHANDLE_CHALLENGE_LRWIZ_TYPE)
    {
        status = TLS_E_INVALID_SEQUENCE;
        goto cleanup;
    }

    if(lpContext->m_ContextHandle == NULL)
    {
        status = TLS_E_INTERNAL;
        goto cleanup;
    }

    if(lpContext->m_ContextType == CONTEXTHANDLE_CHALLENGE_LRWIZ_TYPE)
    {
        dwClientType = CLIENT_TYPE_LRWIZ;
    }
    else
    {
        dwClientType = CLIENT_TYPE_TLSERVER;
    }

    pServerToClientChallenge = (PTLSCHALLENGEDATA)lpContext->m_ContextHandle; 

    //
    // base on client type, verify challenge response data
    //
    status = TLSVerifyChallengeResponse(
                                g_hCryptProv,
                                dwClientType,
                                pServerToClientChallenge,
                                pClientResponse
                            );

    if(status != ERROR_SUCCESS)
    {
        status = TLS_E_INVALID_DATA;
    }
    else
    {
        if(dwClientType == CLIENT_TYPE_LRWIZ)
        {
            lpContext->m_ClientFlags |= CLIENT_ACCESS_LRWIZ;
        }        
        else
        {
            lpContext->m_ClientFlags |= CLIENT_ACCESS_LSERVER;
        }
    }

    if(pServerToClientChallenge != NULL)
    {
        FreeMemory(pServerToClientChallenge->pbChallengeData);
        FreeMemory(pServerToClientChallenge);
    }
        
    lpContext->m_ContextHandle = NULL;
    lpContext->m_ContextType = CONTEXTHANDLE_EMPTY_TYPE;

cleanup:

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_RESPONSESERVERCHALLENGE;
    #endif

    *pdwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcGetTlsPrivateData( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwPrivateDataType,
    /* [switch_is][in] */ PTLSPrivateDataUnion pSearchData,
    /* [ref][out][in] */ PDWORD pdwRetDataType,
    /* [switch_is][out] */ PTLSPrivateDataUnion __RPC_FAR *ppPrivateData,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )

/*++

Abstract:

    Retrieve license server's private data, this include Server's
    unique ID, PID, and registered SPK if any.

Parameters:

    phContext : Client's context handle.
    dwPrivateDataType : Type of private data interested.
    pSearchData : Type of data to search, currently ignore.
    pdwRetDataType : Return data type.
    ppPrivateData : License Server's private data.
    pdwErrCode : Error Code.

Returns:


Note:

    Only LrWiz and License Server can invoke this RPC call.

--*/

{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;
    DWORD cbSource=0;
    PBYTE pbSource=NULL;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcGetTlsPrivateData\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    //
    // relax restriction on who can get private data
    //
    if( dwPrivateDataType != TLS_PRIVATEDATA_PID && 
        dwPrivateDataType != TLS_PRIVATEDATA_UNIQUEID )
    {
        if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_LRWIZ))
        {
            status = TLS_E_ACCESS_DENIED;
            goto cleanup;
        }
    }

    if( dwPrivateDataType < TLS_PRIVATEDATA_MIN ||
        dwPrivateDataType > TLS_PRIVATEDATA_MAX )
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    //
    // Not supported yet...
    //
    if(dwPrivateDataType == TLS_PRIVATEDATA_INSTALLED_CERT)
    {
        status = TLS_E_NOTSUPPORTED;
        goto cleanup;
    }
        
    //
    // Don't really need this but we might need to support
    // re-generate of License Server ID
    //
    if(!AcquireAdministrativeLock(INFINITE))
    {
        status = TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    switch(dwPrivateDataType)
    {
        case TLS_PRIVATEDATA_UNIQUEID:
            pbSource = (PBYTE)g_pszServerUniqueId;
            cbSource = g_cbServerUniqueId;
            break;

        case TLS_PRIVATEDATA_PID:
            pbSource = (PBYTE)g_pszServerPid;
            cbSource = g_cbServerPid;
            break;

        case TLS_PRIVATEDATA_SPK:
            pbSource = g_pbServerSPK;
            cbSource = g_cbServerSPK;
    }

    //
    // Currently, what you ask is what you get.
    //
    *pdwRetDataType = dwPrivateDataType;

    if( (dwPrivateDataType != TLS_PRIVATEDATA_SYSTEMLANGID) && 
        (pbSource == NULL || cbSource == 0) )
    {
        status = TLS_E_RECORD_NOTFOUND;
    }
    else
    {
        *ppPrivateData = (PTLSPrivateDataUnion)midl_user_allocate(sizeof(TLSPrivateDataUnion));
        if(*ppPrivateData != NULL)
        {
            memset(
                    *ppPrivateData,
                    0,
                    sizeof(TLSPrivateDataUnion)
                );

            if(*pdwRetDataType == TLS_PRIVATEDATA_SYSTEMLANGID)
            {
                (*ppPrivateData)->systemLangId = GetSystemDefaultLangID();
            }
            else if(*pdwRetDataType == TLS_PRIVATEDATA_SPK)
            {
                (*ppPrivateData)->SPK.cbSPK = cbSource;
                (*ppPrivateData)->SPK.pbSPK = pbSource;
				(*ppPrivateData)->SPK.pCertExtensions = g_pCertExtensions;

                //(*ppPrivateData)->SPK.pCertExtensions = (PTLSCERT_EXTENSIONS)midl_user_allocate(g_cbCertExtensions);
                //memcpy(
                //        (*ppPrivateData)->SPK.pCertExtensions,
                //        g_pCertExtensions,
                //        g_cbCertExtensions
                //    );
            }
            else
            {
                (*ppPrivateData)->BinaryData.cbData = cbSource;
                (*ppPrivateData)->BinaryData.pbData = pbSource;
            }
        }
        else
        {
            status = ERROR_OUTOFMEMORY;
        }
    }

    ReleaseAdministrativeLock();

cleanup:
    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_GETPRIVATEDATA;
    #endif

    *pdwErrCode = TLSMapReturnCode(status);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcSetTlsPrivateData(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD dwPrivateDataType,
    /* [switch_is][in] */ PTLSPrivateDataUnion pPrivateData,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )

/*++

Abstract:

    Private routine for LrWiz to set license server's private data.

Parameter:

    phContext: Client context handle.
    dwPrivateDataType : Type of private data to set.
    pPrivateData : Private data to set/install.
    pdwErrCode : Server return code.
    
Returns:


Note:

    Only support installing of SPK/Extension at this time.

--*/
{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;
    DWORD dwSpkVerifyResult;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );



    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcDepositeSPK\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_LRWIZ))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    //
    // Only support SPK at this time
    //
    if(dwPrivateDataType != TLS_PRIVATEDATA_SPK)
    {
        status = TLS_E_INVALID_DATA;
        goto cleanup;
    }

    //
    // Lock all RPC calls related to issuing certificate
    //
    if(!AcquireRPCExclusiveLock(INFINITE))
    {
        status = TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    do {
        //if(g_pbServerSPK != NULL && g_cbServerSPK != 0)
        //{
        //    status = TLS_E_SPKALREADYEXIST;
        //    break;
        //}

        if(AcquireAdministrativeLock(INFINITE))
        {
            try {
                status = TLSReGenSelfSignCert(
                                            g_hCryptProv,
                                            pPrivateData->SPK.pbSPK,
                                            pPrivateData->SPK.cbSPK,
                                            pPrivateData->SPK.pCertExtensions->cExtension,
                                            pPrivateData->SPK.pCertExtensions->rgExtension
                                        );
            }
            catch( SE_Exception e ) {
                status = e.getSeNumber();
            }
            catch(...) {
                status = TLS_E_INTERNAL;
            }

            ReleaseAdministrativeLock();
        }
        else
        {
            status = TLS_E_ALLOCATE_HANDLE;
        }            
    } while(FALSE);

    ReleaseRPCExclusiveLock();

cleanup:

    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_SETPRIVATEDATA;
    #endif

    *pdwErrCode = TLSMapReturnCode(status);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcTriggerReGenKey(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ BOOL bRegenKey,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )

/*++

Abstract:

    Private routine to force license server to re-generate its
    public/private key pair, all installed certificates/SPK are
    deleted, User are required to re-register license server.

Parameters:

    phContext : Client context handle.
    bKeepSPKAndExtension : For future use only.
    pdwErrCode : Return error code.

Returns:


++*/

{
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    DWORD status=ERROR_SUCCESS;

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcTriggerReGenKey\n"),
            lpContext->m_Client
        );

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    InterlockedIncrement( &lpContext->m_RefCount );

    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_LRWIZ))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    LPCTSTR pString[1];

    pString[0] = lpContext->m_Client;
    
    TLSLogEventString(
            EVENTLOG_INFORMATION_TYPE,
            TLS_I_TRIGGER_REGENKEY,
            1,
            pString
        );

    //
    // Block ALL RPC calls
    //
    if(!AcquireRPCExclusiveLock(INFINITE))
    {
        status=TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    do {
        if(!AcquireAdministrativeLock(INFINITE))
        {
            status = TLS_E_ALLOCATE_HANDLE;
            break;
        }

        try {
            status = TLSReGenKeysAndReloadServerCert(
                                bRegenKey
                            );
        }
        catch( SE_Exception e ) {
            status = e.getSeNumber();
        }
        catch(...) {
            status = TLS_E_INTERNAL;
        }

        ReleaseAdministrativeLock();

    } while(FALSE);

    ReleaseRPCExclusiveLock();

cleanup:
    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_TRIGGERREGENKEY;
    #endif

    *pdwErrCode = TLSMapReturnCode(status);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcTelephoneRegisterLKP(
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD cbData,
    /* [size_is][in] */ PBYTE pbData,
    /* [ref][out] */ PDWORD pdwErrCode
    )

/*++

--*/

{
    DWORD           status=ERROR_SUCCESS;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    PTLSDbWorkSpace  pDbWkSpace;
    LSKeyPack keypack;

    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcTelephoneRegisterLKP\n"),
            lpContext->m_Client
        );


    InterlockedIncrement( &lpContext->m_RefCount );
    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_LRWIZ))
    {
        status = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
    {
        status=TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    CLEANUPSTMT;
    BEGIN_TRANSACTION(pDbWkSpace);

    try {
        status = TLSDBTelephoneRegisterLicenseKeyPack(
                                            USEHANDLE(pDbWkSpace),
                                            g_pszServerPid,
                                            pbData,
                                            cbData,
                                            &keypack
                                        );
    }
    catch( SE_Exception e ) {
        status = e.getSeNumber();
    }
    catch(...) {
        status = TLS_E_INTERNAL;
    }

    if(TLS_ERROR(status)) 
    {
        ROLLBACK_TRANSACTION(pDbWkSpace);
    }
    else
    {
        COMMIT_TRANSACTION(pDbWkSpace);
    }

    FREEDBHANDLE(pDbWkSpace);

    //
    // Post a sync work object
    //
    if(status == ERROR_SUCCESS)
    {
        if(TLSAnnounceLKPToAllRemoteServer(
                                        keypack.dwKeyPackId,
                                        0
                                    ) != ERROR_SUCCESS)
        {
            TLSLogWarningEvent(TLS_W_ANNOUNCELKP_FAILED);
        }
    }

cleanup:


    lpContext->m_LastError=status;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_TELEPHONEREGISTERLKP;
    #endif


    *pdwErrCode = TLSMapReturnCode(status);

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);

    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcAllocateInternetLicense( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ const CHALLENGE_CONTEXT ChallengeContext,
    /* [in] */ const PTLSLICENSEREQUEST pRequest,
    /* [string][in] */ LPTSTR pMachineName,
    /* [string][in] */ LPTSTR pUserName,
    /* [in] */ const DWORD cbChallengeResponse,
    /* [size_is][in] */ const PBYTE pbChallengeResponse,
    /* [out] */ PDWORD pcbLicense,
    /* [size_is][size_is][out] */ BYTE __RPC_FAR *__RPC_FAR *pbLicense,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++



--*/
{
    return TLSRpcRequestNewLicense(
                                phContext,
                                ChallengeContext,
                                pRequest,
                                pMachineName,
                                pUserName,
                                cbChallengeResponse,
                                pbChallengeResponse,
                                FALSE,
                                pcbLicense,
                                pbLicense,
                                pdwErrCode
                            );

}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcAllocateInternetLicenseEx( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ const CHALLENGE_CONTEXT ChallengeContext,
    /* [in] */ const PTLSLICENSEREQUEST pRequest,
    /* [string][in] */ LPTSTR pMachineName,
    /* [string][in] */ LPTSTR pUserName,
    /* [in] */ const DWORD cbChallengeResponse,
    /* [size_is][in] */ const PBYTE pbChallengeResponse,
    /* [ref][out] */ PTLSInternetLicense pInternetLicense,
    /* [ref][out] */ PDWORD pdwErrCode
    )
/*++

--*/
{
    PBYTE pbLicense = NULL;
    DWORD cbLicense = 0;
    DWORD dwStatus = ERROR_SUCCESS;
    DWORD index = 0;
    PLICENSEDPRODUCT pLicensedProduct = NULL;
    DWORD dwNumLicensedProduct = 0;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;

    if(lpContext == NULL)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        goto cleanup;
    }

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcAllocateInternetLicenseEx\n"),
            lpContext->m_Client
        );

    //
    // Internally forward the request.
    //
    dwStatus = TLSRpcAllocateInternetLicense(
                                        phContext,
                                        ChallengeContext,
                                        pRequest,
                                        pMachineName,
                                        pUserName,
                                        cbChallengeResponse,
                                        pbChallengeResponse,
                                        &cbLicense,
                                        &pbLicense,
                                        pdwErrCode
                                    );

    if(*pdwErrCode >= LSERVER_ERROR_BASE)
    {
        goto cleanup;
    }

    //
    // decode the license.
    //
    dwStatus = LSVerifyDecodeClientLicense(
                            pbLicense, 
                            cbLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            pLicensedProduct
                        );

    //
    // Internet license can only have one licensed product
    //
    if(dwStatus != LICENSE_STATUS_OK || dwNumLicensedProduct == 0 || dwNumLicensedProduct > 1)
    {
        dwStatus = TLS_E_INTERNAL;
        goto cleanup;
    }

    pLicensedProduct = (PLICENSEDPRODUCT)AllocateMemory(
                                                    dwNumLicensedProduct * sizeof(LICENSEDPRODUCT)
                                                );
    if(pLicensedProduct == NULL)
    {
        dwStatus = TLS_E_ALLOCATE_MEMORY;
        goto cleanup;
    }

    dwStatus = LSVerifyDecodeClientLicense(
                            pbLicense, 
                            cbLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            pLicensedProduct
                        );

    if(dwStatus != LICENSE_STATUS_OK)
    {
        dwStatus = TLS_E_INTERNAL;
        goto cleanup;
    }

    //
    // Sets up returns. 
    //
    SAFESTRCPY(pInternetLicense->szServerId, pLicensedProduct->szIssuerId);
    SAFESTRCPY(pInternetLicense->szServerName, pLicensedProduct->szIssuer);
    pInternetLicense->ulSerialNumber = pLicensedProduct->ulSerialNumber;
    pInternetLicense->dwQuantity = pLicensedProduct->dwQuantity;

cleanup:

    lpContext->m_LastError=dwStatus;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_ALLOCATEINTERNETLICNESEEX;
    #endif

    if(*pdwErrCode == ERROR_SUCCESS)
    {
        *pdwErrCode = TLSMapReturnCode(dwStatus);
    }

    if(pLicensedProduct != NULL)
    {
        for(index =0; index < dwNumLicensedProduct; index++)
        {
            LSFreeLicensedProduct(pLicensedProduct+index);
        }

        FreeMemory(pLicensedProduct);
    }

    if(pbLicense != NULL)
    {
        midl_user_free(pbLicense);
    }

    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcReturnInternetLicenseEx( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ const PTLSLICENSEREQUEST pRequest,
    /* [in] */ const ULARGE_INTEGER __RPC_FAR *pulSerialNumber,
    /* [in] */ DWORD dwQuantity,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

--*/
{
    DWORD dwStatus = ERROR_SUCCESS;
    TLSLicenseToBeReturn TobeReturn;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    PTLSDbWorkSpace pDbWorkSpace = NULL;
    CTLSPolicy* pPolicy = NULL;
    PMHANDLE hClient;

    PMLICENSEREQUEST PMLicenseRequest;
    PPMLICENSEREQUEST pAdjustedRequest;

    TCHAR szCompanyName[LSERVER_MAX_STRING_SIZE+2];
    TCHAR szProductId[LSERVER_MAX_STRING_SIZE+2];

    
    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );


    if(VerifyLicenseRequest(pRequest) == FALSE)
    {
        SetLastError(dwStatus = TLS_E_INVALID_DATA);
        goto cleanup;
    }

    if(lpContext == NULL)
    {
        SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
        goto cleanup;
    }

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcReturnInternetLicenseEx\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );
    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_REQUEST))
    {
        dwStatus = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }

    memset(szCompanyName, 0, sizeof(szCompanyName));
    memset(szProductId, 0, sizeof(szProductId));

    memcpy(
            szCompanyName,
            pRequest->ProductInfo.pbCompanyName,
            min(pRequest->ProductInfo.cbCompanyName, sizeof(szCompanyName)-sizeof(TCHAR))
        );

    memcpy(
            szProductId,
            pRequest->ProductInfo.pbProductID,
            min(pRequest->ProductInfo.cbProductID, sizeof(szProductId)-sizeof(TCHAR))
        );

    //
    // Allocate policy module, must have the right policy module to
    // return license.
    //
    pPolicy = AcquirePolicyModule(
                            szCompanyName,
                            szProductId,
                            TRUE
                        );

    if(pPolicy == NULL)
    {
        dwStatus = GetLastError();
        goto cleanup;
    }

    hClient = GenerateClientId();


    //
    // Convert request to PMLICENSEREQUEST
    //
    TlsLicenseRequestToPMLicenseRequest(
                        LICENSETYPE_LICENSE,
                        pRequest,
                        _TEXT(""),
                        _TEXT(""),
                        0,
                        &PMLicenseRequest
                    );

    //
    // Ask policy module the actual product ID
    //
    dwStatus = pPolicy->PMLicenseRequest(
                                hClient,
                                REQUEST_NEW,
                                (PVOID) &PMLicenseRequest,
                                (PVOID *) &pAdjustedRequest
                            );

    memset(&TobeReturn, 0, sizeof(TobeReturn));

    TobeReturn.dwQuantity = dwQuantity;
    TobeReturn.dwKeyPackId = pulSerialNumber->HighPart;
    TobeReturn.dwLicenseId = pulSerialNumber->LowPart;
    TobeReturn.dwPlatformID = pAdjustedRequest->dwPlatformId;
    TobeReturn.cbEncryptedHwid = pRequest->cbEncryptedHwid;
    TobeReturn.pbEncryptedHwid = pRequest->pbEncryptedHwid;
    TobeReturn.dwProductVersion = pAdjustedRequest->dwProductVersion;
    TobeReturn.pszOrgProductId = szProductId;
    TobeReturn.pszCompanyName = szCompanyName;
    TobeReturn.pszProductId = pAdjustedRequest->pszProductId;

    //
    // Allocate DB handle
    //
    if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
    {
        dwStatus = TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    CLEANUPSTMT;
    BEGIN_TRANSACTION(pDbWorkSpace);

    try {
        dwStatus = TLSReturnClientLicensedProduct(
                                        USEHANDLE(pDbWkSpace),
                                        hClient,
                                        pPolicy,
                                        &TobeReturn
                                    );
    }
    catch( SE_Exception e ) {
        dwStatus = e.getSeNumber();
    }
    catch(...) {
        SetLastError(dwStatus = TLS_E_INTERNAL);
    }
    
    if(TLS_ERROR(dwStatus))
    {
        ROLLBACK_TRANSACTION(pDbWorkSpace);
    }
    else
    {
        COMMIT_TRANSACTION(pDbWorkSpace);
    }

    FREEDBHANDLE(pDbWorkSpace);
    
cleanup:

    lpContext->m_LastError=dwStatus;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_RETURNINTERNETLICENSEEX;
    #endif

    *pdwErrCode = TLSMapReturnCode(dwStatus);

    if(pPolicy)
    {
        pPolicy->PMLicenseRequest(
                            hClient,
                            REQUEST_COMPLETE,
                            UlongToPtr (dwStatus),
                            NULL
                        );
        
        ReleasePolicyModule(pPolicy);
    }

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);
    return RPC_S_OK;
}

////////////////////////////////////////////////////////////////////////////

error_status_t 
TLSRpcReturnInternetLicense( 
    /* [in] */ PCONTEXT_HANDLE phContext,
    /* [in] */ DWORD cbLicense,
    /* [size_is][in] */ PBYTE pbLicense,
    /* [ref][out][in] */ PDWORD pdwErrCode
    )
/*++

--*/
{
    DWORD dwStatus = ERROR_SUCCESS;
    DWORD index = 0;
    PLICENSEDPRODUCT pLicensedProduct = NULL;
    DWORD dwNumLicensedProduct = 0;
    TLSLicenseToBeReturn TobeReturn;
    LPCLIENTCONTEXT lpContext = (LPCLIENTCONTEXT)phContext;
    PTLSDbWorkSpace pDbWorkSpace = NULL;
    CTLSPolicy* pPolicy = NULL;
    PMHANDLE hClient;


    _se_translator_function old_trans_se_func = NULL;
    old_trans_se_func = _set_se_translator( trans_se_func );



    if(lpContext == NULL)
    {
        SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
        goto cleanup;
    }

    DBGPrintf(
            DBG_INFORMATION,
            DBG_FACILITY_RPC,
            DBGLEVEL_FUNCTION_TRACE,
            _TEXT("%s : TLSRpcReturnInternetLicense\n"),
            lpContext->m_Client
        );

    InterlockedIncrement( &lpContext->m_RefCount );
    if(!(lpContext->m_ClientFlags & CLIENT_ACCESS_REQUEST))
    {
        dwStatus = TLS_E_ACCESS_DENIED;
        goto cleanup;
    }
    
    // -------------------------------------------------------
    // decode the license.
    // -------------------------------------------------------
    dwStatus = LSVerifyDecodeClientLicense(
                            pbLicense, 
                            cbLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            pLicensedProduct
                        );

    // -------------------------------------------------------
    // Internet license can only have one licensed product
    // -------------------------------------------------------
    if(dwStatus != LICENSE_STATUS_OK || dwNumLicensedProduct == 0 || dwNumLicensedProduct > 1)
    {
        dwStatus = TLS_E_INVALID_LICENSE;
        goto cleanup;
    }

    pLicensedProduct = (PLICENSEDPRODUCT)AllocateMemory(
                                                    dwNumLicensedProduct * sizeof(LICENSEDPRODUCT)
                                                );
    if(pLicensedProduct == NULL)
    {
        dwStatus = TLS_E_ALLOCATE_MEMORY;
        goto cleanup;
    }

    dwStatus = LSVerifyDecodeClientLicense(
                            pbLicense, 
                            cbLicense, 
                            g_pbSecretKey, 
                            g_cbSecretKey,
                            &dwNumLicensedProduct,
                            pLicensedProduct
                        );

    if(dwStatus != LICENSE_STATUS_OK)
    {
        dwStatus = TLS_E_INVALID_LICENSE;
        goto cleanup;
    }


    TobeReturn.dwQuantity = pLicensedProduct->dwQuantity;
    TobeReturn.dwKeyPackId = pLicensedProduct->ulSerialNumber.HighPart;
    TobeReturn.dwLicenseId = pLicensedProduct->ulSerialNumber.LowPart;
    TobeReturn.dwPlatformID = pLicensedProduct->LicensedProduct.dwPlatformID;
    TobeReturn.cbEncryptedHwid = pLicensedProduct->LicensedProduct.cbEncryptedHwid;
    TobeReturn.pbEncryptedHwid = pLicensedProduct->LicensedProduct.pbEncryptedHwid;
    TobeReturn.dwProductVersion = MAKELONG(
                                pLicensedProduct->pLicensedVersion->wMinorVersion,
                                pLicensedProduct->pLicensedVersion->wMajorVersion
                            );

    TobeReturn.pszOrgProductId = (LPTSTR) pLicensedProduct->pbOrgProductID;
    TobeReturn.pszCompanyName = (LPTSTR) pLicensedProduct->LicensedProduct.pProductInfo->pbCompanyName;
    TobeReturn.pszProductId = (LPTSTR) pLicensedProduct->LicensedProduct.pProductInfo->pbProductID;
    TobeReturn.pszUserName = (LPTSTR) pLicensedProduct->szLicensedUser;
    TobeReturn.pszMachineName = pLicensedProduct->szLicensedClient;


    //
    // Allocate policy module, must have the right policy module to
    // return license.
    //
    pPolicy = AcquirePolicyModule(
                            TobeReturn.pszCompanyName,
                            TobeReturn.pszOrgProductId,
                            TRUE
                        );

    if(pPolicy == NULL)
    {
        dwStatus = GetLastError();
        goto cleanup;
    }

    hClient = GenerateClientId();

    //
    // Allocate DB handle
    //
    if(!ALLOCATEDBHANDLE(pDbWkSpace, g_GeneralDbTimeout))
    {
        dwStatus = TLS_E_ALLOCATE_HANDLE;
        goto cleanup;
    }

    CLEANUPSTMT;
    BEGIN_TRANSACTION(pDbWorkSpace);

    try {
        dwStatus = TLSReturnClientLicensedProduct(
                                        USEHANDLE(pDbWkSpace),
                                        hClient,
                                        pPolicy,
                                        &TobeReturn
                                    );
    }
    catch( SE_Exception e ) {
        dwStatus = e.getSeNumber();
    }
    catch(...) {
        SetLastError(dwStatus = TLS_E_INTERNAL);
    }
    
    if(TLS_ERROR(dwStatus))
    {
        ROLLBACK_TRANSACTION(pDbWorkSpace);
    }
    else
    {
        COMMIT_TRANSACTION(pDbWorkSpace);
    }

    FREEDBHANDLE(pDbWorkSpace);
    
cleanup:

    lpContext->m_LastError=dwStatus;
    InterlockedDecrement( &lpContext->m_RefCount );

    #if DBG
    lpContext->m_LastCall = RPC_CALL_RETURNINTERNETLICENSE;
    #endif

    *pdwErrCode = TLSMapReturnCode(dwStatus);

    if(pLicensedProduct != NULL)
    {
        for(index =0; index < dwNumLicensedProduct; index++)
        {
            LSFreeLicensedProduct(pLicensedProduct+index);
        }

        FreeMemory(pLicensedProduct);
    }

    if(pPolicy)
    {
        pPolicy->PMLicenseRequest(
                            hClient,
                            REQUEST_COMPLETE,
                            UlongToPtr (dwStatus),
                            NULL
                        );
        
        ReleasePolicyModule(pPolicy);
    }

    //
    // Reset SE translator
    //
    _set_se_translator(old_trans_se_func);
    return RPC_S_OK;
}