mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4196 lines
107 KiB
4196 lines
107 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996-1998
|
|
//
|
|
// File: licprot.c
|
|
//
|
|
// Contents: Implementation of Hydra Server License Protocol API
|
|
//
|
|
// History: 02-08-00 RobLeit Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "precomp.h"
|
|
#include <rpcnterr.h>
|
|
#include <lmapibuf.h>
|
|
|
|
#include "licemem.inc"
|
|
#include <srvdef.h>
|
|
|
|
VOID
|
|
LogLicensingTimeBombExpirationEvent();
|
|
|
|
void
|
|
ThrottleLicenseLogEvent(
|
|
WORD wEventType,
|
|
DWORD dwEventId,
|
|
WORD cStrings,
|
|
PWCHAR * apwszStrings );
|
|
|
|
LICENSE_STATUS
|
|
LsStatusToLicenseStatus(
|
|
DWORD LsStatus,
|
|
DWORD LsStatusDefault
|
|
);
|
|
|
|
#define LS_DISCOVERY_TIMEOUT (1*1000)
|
|
|
|
// Copied from tlserver\server\srvdef.h
|
|
#define PERMANENT_LICENSE_EXPIRE_DATE INT_MAX
|
|
|
|
#define SECONDS_IN_A_DAY 86400 // number of seconds in a day
|
|
|
|
#define TERMINAL_SERVICE_EVENT_LOG L"TermService"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Global variables
|
|
//
|
|
|
|
HANDLE g_hEventLog = NULL;
|
|
BOOL g_fEventLogOpen = FALSE;
|
|
CRITICAL_SECTION g_EventLogCritSec;
|
|
DWORD g_dwLicenseExpirationLeeway = PERMANENT_LICENSE_LEASE_EXPIRE_LEEWAY;
|
|
DWORD g_dwTerminalServerVersion;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
InitializeProtocolLib()
|
|
{
|
|
LICENSE_STATUS lsStatus;
|
|
|
|
//
|
|
// initialize the cert util library
|
|
//
|
|
|
|
if (LSInitCertutilLib( 0 ))
|
|
{
|
|
__try
|
|
{
|
|
INITLOCK( &g_EventLogCritSec );
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
|
|
return LICENSE_STATUS_OUT_OF_MEMORY;
|
|
}
|
|
|
|
g_hEventLog = RegisterEventSource( NULL, TERMINAL_SERVICE_EVENT_LOG );
|
|
|
|
if (NULL != g_hEventLog)
|
|
{
|
|
g_fEventLogOpen = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return LICENSE_STATUS_SERVER_ABORT;
|
|
}
|
|
|
|
lsStatus = InitializeLicensingTimeBomb();
|
|
|
|
if (lsStatus == LICENSE_STATUS_OK)
|
|
{
|
|
DWORD dwStatus;
|
|
HKEY hKey;
|
|
|
|
DWORD dwOSVersion = GetVersion();
|
|
g_dwTerminalServerVersion = (DWORD)(HIBYTE(LOWORD(dwOSVersion)));
|
|
g_dwTerminalServerVersion |= (DWORD)(LOBYTE(LOWORD(dwOSVersion)) << 16);
|
|
|
|
dwStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, HYDRA_SERVER_PARAM, 0,
|
|
NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey,
|
|
NULL);
|
|
|
|
if (dwStatus == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwBuffer;
|
|
DWORD cbBuffer = sizeof(DWORD);
|
|
|
|
dwStatus = RegQueryValueEx(hKey, PERSEAT_LEEWAY_VALUE, NULL, NULL,
|
|
(LPBYTE)&dwBuffer, &cbBuffer);
|
|
|
|
if (dwStatus == ERROR_SUCCESS)
|
|
{
|
|
g_dwLicenseExpirationLeeway = min(dwBuffer,
|
|
PERMANENT_LICENSE_LEASE_EXPIRE_LEEWAY);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
return lsStatus;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
ShutdownProtocolLib()
|
|
{
|
|
//
|
|
// shut down cert util library
|
|
//
|
|
|
|
g_fEventLogOpen = FALSE;
|
|
|
|
DeregisterEventSource( g_hEventLog );
|
|
|
|
g_hEventLog = NULL;
|
|
|
|
DELETELOCK(&g_EventLogCritSec);
|
|
|
|
LSShutdownCertutilLib();
|
|
|
|
return( LICENSE_STATUS_OK );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
CreateProtocolContext(
|
|
IN LPLICENSE_CAPABILITIES pLicenseCap,
|
|
OUT HANDLE * phContext)
|
|
{
|
|
LICENSE_STATUS Status;
|
|
PHS_Protocol_Context pLicenseContext = NULL;
|
|
|
|
//
|
|
// allocate the protocol context
|
|
//
|
|
|
|
Status = LicenseMemoryAllocate( sizeof( HS_Protocol_Context ), &pLicenseContext );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Note: InitializeCriticalSection could throw an exception during
|
|
// low memory conditions.
|
|
//
|
|
|
|
__try
|
|
{
|
|
INITLOCK( &pLicenseContext->CritSec );
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
|
|
#if DBG
|
|
DbgPrint( "LICPROT: CreateLicenseContext: InitializeCriticalSection exception: 0x%x\n",
|
|
GetExceptionCode() );
|
|
#endif
|
|
|
|
Status = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
goto error;
|
|
}
|
|
|
|
pLicenseContext->hLSHandle = NULL;
|
|
pLicenseContext->State = INIT;
|
|
pLicenseContext->dwProtocolVersion = LICENSE_HIGHEST_PROTOCOL_VERSION;
|
|
pLicenseContext->fAuthenticateServer = TRUE;
|
|
pLicenseContext->CertTypeUsed = CERT_TYPE_INVALID;
|
|
pLicenseContext->dwKeyExchangeAlg = KEY_EXCHANGE_ALG_RSA;
|
|
pLicenseContext->fLoggedProtocolError = FALSE;
|
|
|
|
//
|
|
// Initialize the crypto context parameters
|
|
//
|
|
|
|
pLicenseContext->CryptoContext.dwCryptState = CRYPT_SYSTEM_STATE_INITIALIZED;
|
|
pLicenseContext->CryptoContext.dwSessKeyAlg = BASIC_RC4_128;
|
|
pLicenseContext->CryptoContext.dwMACAlg = MAC_MD5_SHA;
|
|
|
|
|
|
|
|
if (NULL != pLicenseCap)
|
|
{
|
|
//
|
|
// initialize the license context with the incoming data.
|
|
//
|
|
|
|
pLicenseContext->fAuthenticateServer = pLicenseCap->fAuthenticateServer;
|
|
pLicenseContext->dwProtocolVersion = pLicenseCap->ProtocolVer;
|
|
|
|
//
|
|
// If the client is not authenticating the server, this means that
|
|
// the client already has our certificate. But we need to know which
|
|
// certificate the client has.
|
|
//
|
|
|
|
if( FALSE == pLicenseContext->fAuthenticateServer )
|
|
{
|
|
pLicenseContext->CertTypeUsed = pLicenseCap->CertType;
|
|
}
|
|
|
|
//
|
|
// remember the client's machine name
|
|
//
|
|
|
|
if( pLicenseCap->pbClientName )
|
|
{
|
|
Status = LicenseMemoryAllocate(
|
|
pLicenseCap->cbClientName,
|
|
&pLicenseContext->ptszClientMachineName );
|
|
|
|
if( LICENSE_STATUS_OK == Status )
|
|
{
|
|
//
|
|
// copy the client machine name
|
|
//
|
|
|
|
memcpy( pLicenseContext->ptszClientMachineName,
|
|
pLicenseCap->pbClientName,
|
|
pLicenseCap->cbClientName );
|
|
}
|
|
else
|
|
{
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pLicenseContext->ptszClientMachineName = NULL;
|
|
}
|
|
|
|
*phContext = ( HANDLE )pLicenseContext;
|
|
|
|
return( Status );
|
|
|
|
error:
|
|
|
|
//
|
|
// encountered error creating context, free allocated memory before
|
|
// returning
|
|
//
|
|
|
|
if( pLicenseContext )
|
|
{
|
|
if (pLicenseContext->ptszClientMachineName)
|
|
{
|
|
LicenseMemoryFree(&pLicenseContext->ptszClientMachineName);
|
|
}
|
|
|
|
LicenseMemoryFree( &pLicenseContext );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
DeleteProtocolContext(
|
|
HANDLE hContext )
|
|
{
|
|
PHS_Protocol_Context pLicenseContext = ( PHS_Protocol_Context )hContext;
|
|
|
|
if( NULL == pLicenseContext )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_SERVER_CONTEXT );
|
|
}
|
|
|
|
LOCK( &pLicenseContext->CritSec );
|
|
|
|
if (pLicenseContext->hLSHandle != NULL)
|
|
{
|
|
TLSDisconnectFromServer(pLicenseContext->hLSHandle);
|
|
pLicenseContext->hLSHandle = NULL;
|
|
}
|
|
|
|
if( pLicenseContext->ProductInfo.pbCompanyName )
|
|
{
|
|
LicenseMemoryFree( &pLicenseContext->ProductInfo.pbCompanyName );
|
|
}
|
|
|
|
if( pLicenseContext->ProductInfo.pbProductID )
|
|
{
|
|
LicenseMemoryFree( &pLicenseContext->ProductInfo.pbProductID );
|
|
}
|
|
|
|
if( pLicenseContext->ptszClientUserName )
|
|
{
|
|
LicenseMemoryFree( &pLicenseContext->ptszClientUserName );
|
|
}
|
|
|
|
if( pLicenseContext->ptszClientMachineName )
|
|
{
|
|
LicenseMemoryFree( &pLicenseContext->ptszClientMachineName );
|
|
}
|
|
|
|
if( pLicenseContext->pbOldLicense )
|
|
{
|
|
LicenseMemoryFree( &pLicenseContext->pbOldLicense );
|
|
}
|
|
|
|
//
|
|
// Free the license info that's being cached
|
|
//
|
|
|
|
if( pLicenseContext->pTsLicenseInfo )
|
|
{
|
|
LicenseMemoryFree( &pLicenseContext->pTsLicenseInfo );
|
|
}
|
|
|
|
UNLOCK( &pLicenseContext->CritSec );
|
|
|
|
DELETELOCK( &pLicenseContext->CritSec );
|
|
|
|
LicenseMemoryFree( &pLicenseContext );
|
|
|
|
return( LICENSE_STATUS_OK );
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
HandleErrorCondition(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
PDWORD pcbOutBuf,
|
|
PBYTE * ppOutBuf,
|
|
LICENSE_STATUS * pStatus )
|
|
{
|
|
License_Error_Message ErrorMsg;
|
|
LICENSE_STATUS licenseStatus;
|
|
|
|
//
|
|
// returns the correct error code based on the error condition
|
|
//
|
|
|
|
switch( *pStatus )
|
|
{
|
|
case( LICENSE_STATUS_NO_LICENSE_SERVER ):
|
|
|
|
ErrorMsg.dwErrorCode = GM_HS_ERR_NO_LICENSE_SERVER;
|
|
ErrorMsg.dwStateTransition = ST_NO_TRANSITION;
|
|
|
|
break;
|
|
|
|
case( LICENSE_STATUS_INVALID_MAC_DATA ):
|
|
|
|
ErrorMsg.dwErrorCode = GM_HC_ERR_INVALID_MAC;
|
|
ErrorMsg.dwStateTransition = ST_TOTAL_ABORT;
|
|
|
|
break;
|
|
|
|
//
|
|
// Handle all other error conditions as invalid client
|
|
//
|
|
|
|
case( LICENSE_STATUS_INVALID_RESPONSE ):
|
|
default:
|
|
|
|
ErrorMsg.dwErrorCode = GM_HS_ERR_INVALID_CLIENT;
|
|
ErrorMsg.dwStateTransition = ST_TOTAL_ABORT;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// for now, we are not sending any error string
|
|
//
|
|
|
|
ErrorMsg.bbErrorInfo.wBlobLen = 0;
|
|
ErrorMsg.bbErrorInfo.pBlob = NULL;
|
|
|
|
//
|
|
// pack the error message
|
|
//
|
|
|
|
licenseStatus = PackHydraServerErrorMessage(
|
|
pLicenseContext->dwProtocolVersion,
|
|
&ErrorMsg,
|
|
ppOutBuf,
|
|
pcbOutBuf );
|
|
|
|
if( LICENSE_STATUS_OK != licenseStatus )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "HandleErrorConditions: cannot pack error message: 0x%x\n", *pStatus );
|
|
#endif
|
|
*pStatus = LICENSE_STATUS_SERVER_ABORT;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
CreateHydraServerHello(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
DWORD cbInBuf,
|
|
PBYTE pInBuf,
|
|
DWORD * pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
Hydra_Server_License_Request LicenseRequest;
|
|
LICENSE_STATUS Status;
|
|
Binary_Blob ScopeBlob;
|
|
CHAR szScope[] = SCOPE_NAME;
|
|
DWORD dwCertSize;
|
|
|
|
//
|
|
// generate a server random number
|
|
//
|
|
|
|
GenerateRandomBits( LicenseRequest.ServerRandom, LICENSE_RANDOM );
|
|
|
|
memcpy( pLicenseContext->CryptoContext.rgbServerRandom,
|
|
LicenseRequest.ServerRandom,
|
|
LICENSE_RANDOM );
|
|
|
|
//
|
|
// fill in the product info. Allocate memory for and initialize the
|
|
// license context copy of the product info and then just copy the
|
|
// same product info to the license request.
|
|
// NOTE: This info should probably be passed in in the future
|
|
//
|
|
|
|
Status = InitProductInfo(
|
|
&( pLicenseContext->ProductInfo ),
|
|
PRODUCT_INFO_SKU_PRODUCT_ID );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "CreateHydraServerHello: cannot init product info: 0x%x\n", Status );
|
|
#endif
|
|
goto no_request;
|
|
}
|
|
|
|
|
|
memcpy( &LicenseRequest.ProductInfo,
|
|
&pLicenseContext->ProductInfo,
|
|
sizeof( Product_Info ) );
|
|
|
|
//
|
|
// get the hydra server certificate and fill in the key exchange list
|
|
//
|
|
|
|
LicenseRequest.KeyExchngList.wBlobType = BB_KEY_EXCHG_ALG_BLOB;
|
|
LicenseRequest.KeyExchngList.wBlobLen = sizeof( DWORD );
|
|
LicenseRequest.KeyExchngList.pBlob = ( PBYTE )&pLicenseContext->dwKeyExchangeAlg;
|
|
|
|
LicenseRequest.ServerCert.pBlob = NULL;
|
|
LicenseRequest.ServerCert.wBlobLen = 0;
|
|
|
|
//
|
|
// We may or may not have to send the client the certificate depending on whether the
|
|
// client is authenticating the server.
|
|
//
|
|
|
|
if( TRUE == pLicenseContext->fAuthenticateServer )
|
|
{
|
|
//
|
|
// decide on what kind of certificate to get depending on the client's version.
|
|
// Pre-Hydra 5.0 clients only knows how to decode proprietory certificate.
|
|
// Use X509 certificate for all other clients.
|
|
//
|
|
|
|
if( CERT_TYPE_INVALID == pLicenseContext->CertTypeUsed )
|
|
{
|
|
if( PREAMBLE_VERSION_3_0 > GET_PREAMBLE_VERSION( pLicenseContext->dwProtocolVersion ) )
|
|
{
|
|
pLicenseContext->CertTypeUsed = CERT_TYPE_PROPRIETORY;
|
|
}
|
|
else
|
|
{
|
|
pLicenseContext->CertTypeUsed = CERT_TYPE_X509;
|
|
}
|
|
}
|
|
|
|
Status = TLSGetTSCertificate(
|
|
pLicenseContext->CertTypeUsed,
|
|
&LicenseRequest.ServerCert.pBlob,
|
|
&dwCertSize);
|
|
|
|
LicenseRequest.ServerCert.wBlobLen = LOWORD(dwCertSize);
|
|
LicenseRequest.ServerCert.wBlobType = BB_CERTIFICATE_BLOB;
|
|
|
|
if( ( LICENSE_STATUS_OK != Status ) &&
|
|
( CERT_TYPE_X509 == pLicenseContext->CertTypeUsed ) )
|
|
{
|
|
//
|
|
// if we cannot get the X509 certificate chain, use the proprietory
|
|
// certificate.
|
|
//
|
|
|
|
pLicenseContext->CertTypeUsed = CERT_TYPE_PROPRIETORY;
|
|
|
|
Status = TLSGetTSCertificate(
|
|
pLicenseContext->CertTypeUsed,
|
|
&LicenseRequest.ServerCert.pBlob,
|
|
&dwCertSize);
|
|
|
|
LicenseRequest.ServerCert.wBlobLen = LOWORD(dwCertSize);
|
|
LicenseRequest.ServerCert.wBlobType = BB_CERTIFICATE_BLOB;
|
|
|
|
}
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: cannot get server certificate: %x\n", Status );
|
|
#endif
|
|
goto no_request;
|
|
}
|
|
}
|
|
|
|
//
|
|
// fill in the scope info. This info may be passed in in the future.
|
|
//
|
|
|
|
LicenseRequest.ScopeList.dwScopeCount = 1;
|
|
LicenseRequest.ScopeList.Scopes = &ScopeBlob;
|
|
|
|
ScopeBlob.wBlobType = BB_SCOPE_BLOB;
|
|
ScopeBlob.pBlob = szScope;
|
|
ScopeBlob.wBlobLen = strlen( ScopeBlob.pBlob ) + 1;
|
|
|
|
strcpy( pLicenseContext->Scope, ScopeBlob.pBlob );
|
|
|
|
//
|
|
// Pack the server hello message into network format
|
|
//
|
|
|
|
Status = PackHydraServerLicenseRequest(
|
|
pLicenseContext->dwProtocolVersion,
|
|
&LicenseRequest,
|
|
ppOutBuf,
|
|
pcbOutBuf );
|
|
|
|
//
|
|
// free the memory containing the server certificate
|
|
//
|
|
|
|
if( LicenseRequest.ServerCert.pBlob )
|
|
{
|
|
TLSFreeTSCertificate( LicenseRequest.ServerCert.pBlob );
|
|
LicenseRequest.ServerCert.pBlob = NULL;
|
|
}
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto no_request;
|
|
}
|
|
|
|
Status = LICENSE_STATUS_CONTINUE;
|
|
|
|
//
|
|
// change the state of the context
|
|
//
|
|
|
|
pLicenseContext->State = SENT_SERVER_HELLO;
|
|
|
|
return( Status );
|
|
|
|
//=========================================================================
|
|
// Error return
|
|
//=========================================================================
|
|
|
|
no_request:
|
|
|
|
//
|
|
// free memory and handles
|
|
//
|
|
|
|
if( pLicenseContext->ProductInfo.pbCompanyName )
|
|
{
|
|
LicenseMemoryFree( &pLicenseContext->ProductInfo.pbCompanyName );
|
|
}
|
|
|
|
if( pLicenseContext->ProductInfo.pbProductID )
|
|
{
|
|
LicenseMemoryFree( &pLicenseContext->ProductInfo.pbProductID );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
HandleHelloResponse(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
DWORD cbInBuf,
|
|
PBYTE pInBuf,
|
|
DWORD * pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
PPreamble pPreamble;
|
|
|
|
ASSERT( NULL != pInBuf );
|
|
ASSERT( cbInBuf > sizeof( Preamble ) );
|
|
|
|
if( ( NULL == pInBuf ) || ( sizeof( Preamble ) > cbInBuf ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
//
|
|
// check the message preamble to determine how to unpack the message
|
|
//
|
|
|
|
pPreamble = ( PPreamble )pInBuf;
|
|
|
|
if( HC_LICENSE_INFO == pPreamble->bMsgType )
|
|
{
|
|
//
|
|
// Client has sent us its license
|
|
//
|
|
|
|
return( HandleClientLicense( pLicenseContext, cbInBuf, pInBuf, pcbOutBuf, ppOutBuf ) );
|
|
|
|
}
|
|
else if( HC_NEW_LICENSE_REQUEST == pPreamble->bMsgType )
|
|
{
|
|
//
|
|
// Client has requested for a new license
|
|
//
|
|
|
|
return( HandleNewLicenseRequest( pLicenseContext, cbInBuf, pInBuf, pcbOutBuf, ppOutBuf ) );
|
|
|
|
}
|
|
else if( GM_ERROR_ALERT == pPreamble->bMsgType )
|
|
{
|
|
//
|
|
// Client has encountered an error
|
|
//
|
|
|
|
return( HandleClientError( pLicenseContext, cbInBuf, pInBuf, pcbOutBuf, ppOutBuf ) );
|
|
}
|
|
|
|
//
|
|
// The client response is invalid for the current server state
|
|
//
|
|
|
|
return( LICENSE_STATUS_INVALID_RESPONSE );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
ChooseLicense(
|
|
PValidation_Info pValidationInfo,
|
|
DWORD dwNumLicenses,
|
|
LICENSEDPRODUCT * pLicenseInfo,
|
|
LPDWORD pdwLicenseIndex,
|
|
BOOL fMatchingVersion )
|
|
{
|
|
DWORD
|
|
dwCurrentLicense,
|
|
dwProductVersion;
|
|
LICENSEDPRODUCT *
|
|
pCurrentLicense = pLicenseInfo;
|
|
BOOL
|
|
fFoundLicense = FALSE;
|
|
|
|
if( ( 0 >= dwNumLicenses ) || ( NULL == pLicenseInfo ) || ( NULL == pdwLicenseIndex ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
//
|
|
// Find a license with the license array that matches the criteria.
|
|
// The caller may be looking for a license that matches the current product
|
|
// version, or for a license that is later than the current product version.
|
|
//
|
|
|
|
for( dwCurrentLicense = 0; dwCurrentLicense < dwNumLicenses; dwCurrentLicense++ )
|
|
{
|
|
if( TERMSERV_CERT_VERSION_BETA == pCurrentLicense->dwLicenseVersion )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
dwProductVersion = pCurrentLicense->pLicensedVersion->wMajorVersion;
|
|
dwProductVersion <<= 16;
|
|
dwProductVersion |= pCurrentLicense->pLicensedVersion->wMinorVersion;
|
|
|
|
if( fMatchingVersion )
|
|
{
|
|
//
|
|
// we should be looking for a license with a matching version
|
|
//
|
|
|
|
if( dwProductVersion == pValidationInfo->pProductInfo->dwVersion )
|
|
{
|
|
fFoundLicense = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Looking for a license that is later than the current product
|
|
// version.
|
|
//
|
|
|
|
if( dwProductVersion > pValidationInfo->pProductInfo->dwVersion )
|
|
{
|
|
fFoundLicense = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// continue looking for the license
|
|
//
|
|
|
|
pCurrentLicense++;
|
|
}
|
|
|
|
if( FALSE == fFoundLicense )
|
|
{
|
|
return( LICENSE_STATUS_NO_LICENSE_ERROR );
|
|
}
|
|
|
|
*pdwLicenseIndex = dwCurrentLicense;
|
|
|
|
return( LICENSE_STATUS_OK );
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
UpdateVerifyResult(
|
|
LICENSE_STATUS * pCurrentStatus,
|
|
LICENSE_STATUS NewStatus )
|
|
{
|
|
//
|
|
// Update the current status with the best result so far.
|
|
// The ratings of the license verification result are as follows:
|
|
//
|
|
// (1) LICENSE_STATUS_OK
|
|
// (2) LICENSE_STATUS_SHOULD_UPGRADE_LICENSE
|
|
// (3) LICENSE_STATUS_MUST_UPGRADE_LICENSE
|
|
// (4) Other LICENSE_STATUS_xxx
|
|
//
|
|
|
|
if( LICENSE_STATUS_OK == *pCurrentStatus )
|
|
{
|
|
return;
|
|
}
|
|
else if( LICENSE_STATUS_OK == NewStatus )
|
|
{
|
|
*pCurrentStatus = NewStatus;
|
|
return;
|
|
}
|
|
|
|
if( LICENSE_STATUS_SHOULD_UPGRADE_LICENSE == *pCurrentStatus )
|
|
{
|
|
return;
|
|
}
|
|
else if( LICENSE_STATUS_SHOULD_UPGRADE_LICENSE == NewStatus )
|
|
{
|
|
*pCurrentStatus = NewStatus;
|
|
return;
|
|
}
|
|
|
|
if( LICENSE_STATUS_MUST_UPGRADE_LICENSE == *pCurrentStatus )
|
|
{
|
|
return;
|
|
}
|
|
else if( LICENSE_STATUS_MUST_UPGRADE_LICENSE == NewStatus )
|
|
{
|
|
*pCurrentStatus = NewStatus;
|
|
return;
|
|
}
|
|
|
|
*pCurrentStatus = NewStatus;
|
|
return;
|
|
}
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
FreeTsLicenseInfo
|
|
|
|
Description:
|
|
|
|
Release all the memory used in the given TS_LICENSE_INFO structure
|
|
|
|
Parameter:
|
|
|
|
pTsLicenseInfo - Pointer to a TS_LICENSE_INFO structure
|
|
|
|
Return:
|
|
|
|
Nothing.
|
|
|
|
--*/
|
|
|
|
VOID
|
|
FreeTsLicenseInfo(
|
|
PTS_LICENSE_INFO pTsLicenseInfo )
|
|
{
|
|
if( NULL == pTsLicenseInfo )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( pTsLicenseInfo->pbRawLicense )
|
|
{
|
|
LicenseMemoryFree( &pTsLicenseInfo->pbRawLicense );
|
|
}
|
|
|
|
//
|
|
// release all memory within the structure
|
|
//
|
|
|
|
memset( pTsLicenseInfo, 0, sizeof( TS_LICENSE_INFO ) );
|
|
|
|
return;
|
|
}
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
CacheLicenseInfo
|
|
|
|
Description:
|
|
|
|
Cache the client licensing info
|
|
|
|
Parameters:
|
|
|
|
pLicenseContext - Pointer to license protocol context
|
|
pCurrentLicense - Pointer to the license info to cache
|
|
|
|
Returns:
|
|
|
|
nothing.
|
|
|
|
--*/
|
|
|
|
VOID
|
|
CacheLicenseInfo(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
PLICENSEDPRODUCT pCurrentLicense )
|
|
{
|
|
LICENSE_STATUS
|
|
Status;
|
|
|
|
//
|
|
// free the old information in the cache
|
|
//
|
|
|
|
if( pLicenseContext->pTsLicenseInfo )
|
|
{
|
|
FreeTsLicenseInfo( pLicenseContext->pTsLicenseInfo );
|
|
}
|
|
else
|
|
{
|
|
Status = LicenseMemoryAllocate( sizeof( TS_LICENSE_INFO ), &pLicenseContext->pTsLicenseInfo );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICEMGR: CacheLicenseInfo: cannot allocate memory for license info cache\n" );
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// decide if the license is temporary
|
|
//
|
|
|
|
if( pCurrentLicense->pLicensedVersion->dwFlags & 0x80000000 )
|
|
{
|
|
pLicenseContext->pTsLicenseInfo->fTempLicense = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pLicenseContext->pTsLicenseInfo->fTempLicense = FALSE;
|
|
}
|
|
|
|
//
|
|
// cache license validity dates
|
|
//
|
|
|
|
pLicenseContext->pTsLicenseInfo->NotAfter = pCurrentLicense->NotAfter;
|
|
|
|
return;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
ValidateHydraLicense(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
PValidation_Info pValidationInfo,
|
|
DWORD dwNumLicenses,
|
|
PLICENSEDPRODUCT pLicenseInfo,
|
|
PDWORD pdwLicenseState )
|
|
{
|
|
LICENSE_STATUS
|
|
Status = LICENSE_STATUS_INVALID_LICENSE,
|
|
CurrentStatus;
|
|
DWORD
|
|
dwLicenseIndex = 0,
|
|
dwCurrentLicense = 0;
|
|
PLICENSEDPRODUCT
|
|
pCurrentLicense;
|
|
BOOL
|
|
fFoundMatchingVersion = FALSE;
|
|
|
|
//
|
|
// The client could have given us multiple licenses. Pick the right
|
|
// license from the array of licenses to validate. Always try to pick
|
|
// the license that matches the current product version before looking
|
|
// for a license that is for a later version.
|
|
//
|
|
|
|
CurrentStatus = ChooseLicense(
|
|
pValidationInfo,
|
|
dwNumLicenses,
|
|
pLicenseInfo,
|
|
&dwLicenseIndex,
|
|
TRUE );
|
|
|
|
if( LICENSE_STATUS_OK == CurrentStatus )
|
|
{
|
|
//
|
|
// Verify the license that is the same version as the current product
|
|
// version
|
|
|
|
// initialize the license state
|
|
//
|
|
|
|
LicenseInitState( *pdwLicenseState );
|
|
pCurrentLicense = pLicenseInfo + dwLicenseIndex;
|
|
fFoundMatchingVersion = TRUE;
|
|
|
|
//
|
|
// verify HWID
|
|
//
|
|
|
|
CurrentStatus = VerifyClientHwid( pLicenseContext, pValidationInfo, pCurrentLicense );
|
|
|
|
if( LICENSE_STATUS_OK != CurrentStatus )
|
|
{
|
|
UpdateVerifyResult( &Status, CurrentStatus );
|
|
goto verify_later_license;
|
|
}
|
|
|
|
//
|
|
// verify product info. Also verifies the product version.
|
|
// The product version determines if the license needs to be
|
|
// upgraded or not.
|
|
//
|
|
|
|
CurrentStatus = VerifyLicenseProductInfo(
|
|
pLicenseContext,
|
|
pValidationInfo,
|
|
pCurrentLicense,
|
|
pdwLicenseState );
|
|
|
|
if( LICENSE_STATUS_OK != CurrentStatus )
|
|
{
|
|
UpdateVerifyResult( &Status, CurrentStatus );
|
|
goto verify_later_license;
|
|
}
|
|
|
|
//
|
|
// verify license valid date and time. This validation is only
|
|
// needed if it is a temporary license
|
|
//
|
|
|
|
CurrentStatus = VerifyLicenseDateAndTime( pCurrentLicense, pdwLicenseState );
|
|
|
|
if( LICENSE_STATUS_OK != CurrentStatus )
|
|
{
|
|
UpdateVerifyResult( &Status, CurrentStatus );
|
|
goto verify_later_license;
|
|
}
|
|
|
|
CurrentStatus = GetVerifyResult( *pdwLicenseState );
|
|
UpdateVerifyResult( &Status, CurrentStatus );
|
|
|
|
//
|
|
// cache the license we tried to validate
|
|
//
|
|
|
|
CacheLicenseInfo( pLicenseContext, pCurrentLicense );
|
|
|
|
//
|
|
// If the current license is OK, then we're done verifying
|
|
//
|
|
|
|
if( LICENSE_STATUS_OK == Status )
|
|
{
|
|
return( Status );
|
|
}
|
|
}
|
|
|
|
verify_later_license:
|
|
|
|
//
|
|
// Cannot find or did not sucessfully verify a license that matches the current
|
|
// product version. The following code finds and verifies licenses that
|
|
// are later than the current product version.
|
|
//
|
|
|
|
CurrentStatus = ChooseLicense(
|
|
pValidationInfo,
|
|
dwNumLicenses,
|
|
pLicenseInfo,
|
|
&dwLicenseIndex,
|
|
FALSE );
|
|
|
|
if( LICENSE_STATUS_OK != CurrentStatus )
|
|
{
|
|
|
|
if( FALSE == fFoundMatchingVersion )
|
|
{
|
|
//
|
|
// cannot find a license that is the same or later than the current
|
|
// product version ==> this license must be upgraded.
|
|
//
|
|
|
|
LicenseSetState( *pdwLicenseState, LICENSE_STATE_OLD_VERSION );
|
|
return( GetVerifyResult( *pdwLicenseState ) );
|
|
}
|
|
else
|
|
{
|
|
return( Status );
|
|
}
|
|
}
|
|
|
|
pCurrentLicense = pLicenseInfo + dwLicenseIndex;
|
|
dwCurrentLicense = dwLicenseIndex;
|
|
|
|
while( dwCurrentLicense < dwNumLicenses )
|
|
{
|
|
//
|
|
// initialize the license state
|
|
//
|
|
|
|
LicenseInitState( *pdwLicenseState );
|
|
|
|
//
|
|
// verify HWID
|
|
//
|
|
|
|
CurrentStatus = VerifyClientHwid( pLicenseContext, pValidationInfo, pCurrentLicense );
|
|
|
|
if( LICENSE_STATUS_OK != CurrentStatus )
|
|
{
|
|
UpdateVerifyResult( &Status, CurrentStatus );
|
|
goto next_license;
|
|
}
|
|
|
|
//
|
|
// verify product info. Also verifies the product version.
|
|
// The product version determines if the license needs to be
|
|
// upgraded or not.
|
|
//
|
|
|
|
CurrentStatus = VerifyLicenseProductInfo(
|
|
pLicenseContext,
|
|
pValidationInfo,
|
|
pCurrentLicense,
|
|
pdwLicenseState );
|
|
|
|
if( LICENSE_STATUS_OK != CurrentStatus )
|
|
{
|
|
UpdateVerifyResult( &Status, CurrentStatus );
|
|
goto next_license;
|
|
}
|
|
|
|
//
|
|
// verify license valid date and time. This validation is only
|
|
// needed if it is a temporary license
|
|
//
|
|
|
|
CurrentStatus = VerifyLicenseDateAndTime( pCurrentLicense, pdwLicenseState );
|
|
|
|
if( LICENSE_STATUS_OK != CurrentStatus )
|
|
{
|
|
UpdateVerifyResult( &Status, CurrentStatus );
|
|
goto next_license;
|
|
}
|
|
|
|
CurrentStatus = GetVerifyResult( *pdwLicenseState );
|
|
|
|
UpdateVerifyResult( &Status, CurrentStatus );
|
|
|
|
//
|
|
// cache the info of the license we had just try to validate
|
|
//
|
|
|
|
CacheLicenseInfo( pLicenseContext, pCurrentLicense );
|
|
|
|
if( LICENSE_STATUS_OK == Status )
|
|
{
|
|
//
|
|
// if the license is OK, then we can stop the verification process
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
next_license:
|
|
|
|
//
|
|
// Get the next license that is later than the current product version.
|
|
//
|
|
|
|
if( dwNumLicenses <= ++dwCurrentLicense )
|
|
{
|
|
break;
|
|
}
|
|
|
|
pCurrentLicense++;
|
|
|
|
CurrentStatus = ChooseLicense(
|
|
pValidationInfo,
|
|
dwNumLicenses - dwCurrentLicense,
|
|
pCurrentLicense,
|
|
&dwLicenseIndex,
|
|
FALSE );
|
|
|
|
if( LICENSE_STATUS_OK != CurrentStatus )
|
|
{
|
|
break;
|
|
}
|
|
|
|
pCurrentLicense += dwLicenseIndex;
|
|
dwCurrentLicense += dwLicenseIndex;
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
ValidateLicense(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
PValidation_Info pValidationInfo,
|
|
PDWORD pdwLicenseState,
|
|
BOOL fCheckForPermanent )
|
|
{
|
|
LICENSE_STATUS Status;
|
|
DWORD dwNumLicenseInfo = 0;
|
|
LICENSEDPRODUCT * pLicenseInfo = NULL;
|
|
static DWORD cchComputerName;
|
|
static TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
DWORD cbSecretKey = 0;
|
|
PBYTE pbSecretKey = NULL;
|
|
|
|
if( NULL == pLicenseContext )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
//
|
|
// Get the secret key that is used to encrypt the HWID
|
|
//
|
|
|
|
LicenseGetSecretKey( &cbSecretKey, NULL );
|
|
|
|
Status = LicenseMemoryAllocate( cbSecretKey, &pbSecretKey );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
Status = LicenseGetSecretKey( &cbSecretKey, pbSecretKey );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// decode license issued by hydra license server certificate engine.
|
|
// Decoding the license will also get us back the decrypted HWID.
|
|
//
|
|
|
|
__try
|
|
{
|
|
Status = LSVerifyDecodeClientLicense(
|
|
pValidationInfo->pLicense,
|
|
pValidationInfo->cbLicense,
|
|
pbSecretKey,
|
|
cbSecretKey,
|
|
&dwNumLicenseInfo,
|
|
NULL );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
Status = LicenseMemoryAllocate(
|
|
sizeof( LICENSEDPRODUCT ) * dwNumLicenseInfo,
|
|
&pLicenseInfo );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
Status = LSVerifyDecodeClientLicense(
|
|
pValidationInfo->pLicense,
|
|
pValidationInfo->cbLicense,
|
|
pbSecretKey,
|
|
cbSecretKey,
|
|
&dwNumLicenseInfo,
|
|
pLicenseInfo );
|
|
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DWORD dwExceptionCode = GetExceptionCode();
|
|
Status = LICENSE_STATUS_CANNOT_DECODE_LICENSE;
|
|
}
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICEMGR: cannot decode license: 0x%x\n", Status );
|
|
#endif
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// now validate the license
|
|
//
|
|
|
|
Status = ValidateHydraLicense(
|
|
pLicenseContext,
|
|
pValidationInfo,
|
|
dwNumLicenseInfo,
|
|
pLicenseInfo,
|
|
pdwLicenseState );
|
|
|
|
|
|
if (fCheckForPermanent
|
|
&& LICENSE_STATUS_OK == Status
|
|
&& !pLicenseContext->pTsLicenseInfo->fTempLicense
|
|
&& pLicenseContext->ProductInfo.cbProductID >= sizeof(TERMSERV_FREE_TYPE))
|
|
{
|
|
int i;
|
|
TCHAR *pszT;
|
|
|
|
for (i = 0, pszT = (TCHAR *)(pLicenseContext->ProductInfo.pbProductID + pLicenseContext->ProductInfo.cbProductID - sizeof(TERMSERV_FREE_TYPE)); i < sizeof(TERMSERV_FREE_TYPE); i++)
|
|
{
|
|
if (TERMSERV_FREE_TYPE[i] != pszT[i])
|
|
goto done;
|
|
}
|
|
|
|
ReceivedPermanentLicense();
|
|
}
|
|
|
|
done:
|
|
|
|
if( pbSecretKey )
|
|
{
|
|
LicenseMemoryFree( &pbSecretKey );
|
|
}
|
|
|
|
//
|
|
// Free the array of licensed product info
|
|
//
|
|
|
|
if( pLicenseInfo )
|
|
{
|
|
while( dwNumLicenseInfo-- )
|
|
{
|
|
LSFreeLicensedProduct( pLicenseInfo + dwNumLicenseInfo );
|
|
}
|
|
|
|
LicenseMemoryFree( &pLicenseInfo );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
HandleClientLicense(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
DWORD cbInBuf,
|
|
PBYTE pInBuf,
|
|
DWORD * pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
LICENSE_STATUS Status, UpgradeStatus;
|
|
Hydra_Client_License_Info LicenseInfo;
|
|
PBYTE pPreMasterSecret = NULL;
|
|
DWORD dwPreMasterSecretLen = 0;
|
|
HWID Hwid;
|
|
Validation_Info ValidationInfo;
|
|
License_Error_Message ErrorMsg;
|
|
DWORD dwLicenseState = 0;
|
|
BYTE MacData[LICENSE_MAC_DATA];
|
|
DWORD CertType;
|
|
|
|
ASSERT( NULL != pInBuf );
|
|
ASSERT( cbInBuf > 0 );
|
|
|
|
if( ( NULL == pInBuf ) || ( 0 >= cbInBuf ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
//
|
|
// Unpack the client license info message
|
|
//
|
|
|
|
InitBinaryBlob( &LicenseInfo.EncryptedPreMasterSecret );
|
|
InitBinaryBlob( &LicenseInfo.LicenseInfo );
|
|
InitBinaryBlob( &LicenseInfo.EncryptedHWID );
|
|
|
|
Status = UnPackHydraClientLicenseInfo( pInBuf, cbInBuf, &LicenseInfo );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
//
|
|
// Initialize the crypto context with the key exchange info and build the pre-master
|
|
// secret. We need the server and client random numbers and the pre-master secret
|
|
// to build the pre-master secret.
|
|
//
|
|
|
|
memcpy( pLicenseContext->CryptoContext.rgbClientRandom,
|
|
LicenseInfo.ClientRandom,
|
|
LICENSE_RANDOM );
|
|
|
|
pLicenseContext->CryptoContext.dwKeyExchAlg = LicenseInfo.dwPrefKeyExchangeAlg;
|
|
|
|
dwPreMasterSecretLen = LICENSE_PRE_MASTER_SECRET;
|
|
|
|
Status = GetEnvelopedData( pLicenseContext->CertTypeUsed,
|
|
LicenseInfo.EncryptedPreMasterSecret.pBlob,
|
|
( DWORD )LicenseInfo.EncryptedPreMasterSecret.wBlobLen,
|
|
&pPreMasterSecret,
|
|
&dwPreMasterSecretLen );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
if (Status == LICENSE_STATUS_INVALID_INPUT)
|
|
{
|
|
Status = LICENSE_STATUS_INVALID_RESPONSE;
|
|
}
|
|
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
//
|
|
// Set the pre-master secret and generate the master secret
|
|
//
|
|
|
|
Status = LicenseSetPreMasterSecret( &pLicenseContext->CryptoContext, pPreMasterSecret );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
Status = LicenseBuildMasterSecret( &pLicenseContext->CryptoContext );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
//
|
|
// Derive the session key from the key exchange info
|
|
//
|
|
|
|
Status = LicenseMakeSessionKeys( &pLicenseContext->CryptoContext, 0 );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
//
|
|
// Use the session key to decrypt the HWID
|
|
//
|
|
|
|
if( LicenseInfo.EncryptedHWID.wBlobLen > sizeof(Hwid) )
|
|
{
|
|
Status = LICENSE_STATUS_INVALID_MAC_DATA;
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
memcpy( &Hwid,
|
|
LicenseInfo.EncryptedHWID.pBlob,
|
|
LicenseInfo.EncryptedHWID.wBlobLen );
|
|
|
|
Status = LicenseDecryptSessionData( &pLicenseContext->CryptoContext,
|
|
( PBYTE )&Hwid,
|
|
( DWORD )LicenseInfo.EncryptedHWID.wBlobLen );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
//
|
|
// Calculate the MAC on the HWID.
|
|
//
|
|
|
|
Status = LicenseGenerateMAC( &pLicenseContext->CryptoContext,
|
|
( PBYTE )&Hwid,
|
|
sizeof( HWID ),
|
|
MacData);
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
Status = LICENSE_STATUS_INVALID_MAC_DATA;
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
//
|
|
// now verify the MAC data
|
|
//
|
|
|
|
if( 0 != memcmp( MacData, LicenseInfo.MACData, LICENSE_MAC_DATA ) )
|
|
{
|
|
Status = LICENSE_STATUS_INVALID_MAC_DATA;
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
//
|
|
// keep track of the client platform ID
|
|
//
|
|
|
|
pLicenseContext->dwClientPlatformID = LicenseInfo.dwPlatformID;
|
|
|
|
//
|
|
// call the license manager to validate the license.
|
|
// For now, we don't have to fill in the product info fields
|
|
//
|
|
|
|
ValidationInfo.pValidationData = ( PBYTE )&Hwid;
|
|
ValidationInfo.cbValidationData = LICENSE_HWID_LENGTH;
|
|
ValidationInfo.pProductInfo = &pLicenseContext->ProductInfo;
|
|
ValidationInfo.pLicense = LicenseInfo.LicenseInfo.pBlob;
|
|
ValidationInfo.cbLicense = ( DWORD )LicenseInfo.LicenseInfo.wBlobLen;
|
|
|
|
Status = ValidateLicense( pLicenseContext,
|
|
&ValidationInfo,
|
|
&dwLicenseState,
|
|
FALSE // fCheckForPermanent
|
|
);
|
|
|
|
//
|
|
// If the license cannot be decoded, then it is time to issue a new license
|
|
// for the client.
|
|
//
|
|
|
|
if( LICENSE_STATUS_CANNOT_DECODE_LICENSE == Status ||
|
|
LICENSE_STATUS_INVALID_LICENSE == Status )
|
|
{
|
|
LICENSE_STATUS StatusT = IssuePlatformChallenge( pLicenseContext, pcbOutBuf, ppOutBuf );
|
|
|
|
if( LICENSE_STATUS_OK != StatusT )
|
|
{
|
|
//
|
|
// cannot obtain a platform challenge for the client
|
|
//
|
|
|
|
#if DBG
|
|
DbgPrint( "LICPROT: cannot issue platform challenge: 0x%x\n", Status );
|
|
#endif
|
|
goto construct_return_msg;
|
|
}
|
|
|
|
pLicenseContext->State = ISSUED_PLATFORM_CHALLENGE;
|
|
Status = LICENSE_STATUS_CONTINUE;
|
|
goto done;
|
|
}
|
|
|
|
#ifdef UPGRADE_LICENSE
|
|
|
|
//
|
|
// check if the license needs to be upgraded.
|
|
//
|
|
|
|
if( ( LICENSE_STATUS_MUST_UPGRADE_LICENSE == Status ) ||
|
|
( LICENSE_STATUS_SHOULD_UPGRADE_LICENSE == Status ) )
|
|
{
|
|
//
|
|
// issue the platform challenge for upgrading a license
|
|
//
|
|
|
|
UpgradeStatus = IssuePlatformChallenge(
|
|
pLicenseContext,
|
|
pcbOutBuf,
|
|
ppOutBuf );
|
|
|
|
if( LICENSE_STATUS_OK == UpgradeStatus )
|
|
{
|
|
//
|
|
// keep track of the old license and continue with the licensing
|
|
// protocol. We will upgrade the old license when the client
|
|
// returns with the platform challenge.
|
|
//
|
|
|
|
if( pLicenseContext->pbOldLicense )
|
|
{
|
|
LicenseMemoryFree( &pLicenseContext->pbOldLicense );
|
|
}
|
|
|
|
pLicenseContext->pbOldLicense = LicenseInfo.LicenseInfo.pBlob;
|
|
pLicenseContext->cbOldLicense = LicenseInfo.LicenseInfo.wBlobLen;
|
|
|
|
pLicenseContext->State = ISSUED_PLATFORM_CHALLENGE;
|
|
Status = LICENSE_STATUS_CONTINUE;
|
|
|
|
goto done;
|
|
}
|
|
else if( LICENSE_STATUS_SHOULD_UPGRADE_LICENSE == Status )
|
|
{
|
|
//
|
|
// Let the client go through if we cannot issue a platform challenge to
|
|
// upgrade a valid license now.
|
|
//
|
|
|
|
Status = LICENSE_STATUS_OK;
|
|
goto construct_return_msg;
|
|
}
|
|
else
|
|
{
|
|
// LICENSE_STATUS_MUST_UPGRADE_LICENSE: send back the real error
|
|
|
|
Status = UpgradeStatus;
|
|
}
|
|
|
|
//
|
|
// cannot issue platform challenge to upgrade a license that is not good
|
|
// any more.
|
|
//
|
|
|
|
#if DBG
|
|
DbgPrint( "LICPROT: cannot issue platform challenge to upgrade license: 0x%x\n", Status );
|
|
#endif
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
//
|
|
// we are ignoring license upgrade
|
|
//
|
|
|
|
if( LICENSE_STATUS_SHOULD_UPGRADE_LICENSE == Status )
|
|
{
|
|
//
|
|
// change the status to OK
|
|
//
|
|
|
|
Status = LICENSE_STATUS_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// now construct the message to return to the client, based on the current
|
|
// status code
|
|
//
|
|
|
|
construct_return_msg:
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
//
|
|
// The current status states that the client could not be validated
|
|
// due to some error
|
|
//
|
|
|
|
#if DBG
|
|
DbgPrint( "HandleClientLicense: constructing error message: 0x%x\n", Status );
|
|
#endif
|
|
|
|
//
|
|
// handle the error condition and update our state
|
|
//
|
|
|
|
HandleErrorCondition( pLicenseContext, pcbOutBuf, ppOutBuf, &Status );
|
|
|
|
pLicenseContext->State = VALIDATION_ERROR;
|
|
|
|
if( (LICENSE_STATUS_INVALID_RESPONSE == Status)
|
|
|| (LICENSE_STATUS_INVALID_MAC_DATA == Status)
|
|
|| (LICENSE_STATUS_CANNOT_DECODE_LICENSE == Status)
|
|
|| (LICENSE_STATUS_INVALID_LICENSE == Status) )
|
|
{
|
|
WORD wLogString = 0;
|
|
LPTSTR ptszLogString[1] = { NULL };
|
|
|
|
//
|
|
// Log the failure
|
|
//
|
|
|
|
if( pLicenseContext->ptszClientMachineName )
|
|
{
|
|
wLogString = 1;
|
|
ptszLogString[0] = pLicenseContext->ptszClientMachineName;
|
|
}
|
|
|
|
LicenseLogEvent( EVENTLOG_INFORMATION_TYPE,
|
|
EVENT_INVALID_LICENSE,
|
|
wLogString, ptszLogString );
|
|
|
|
pLicenseContext->fLoggedProtocolError = TRUE;
|
|
|
|
}
|
|
else if ((NULL != pLicenseContext->pTsLicenseInfo)
|
|
&& (!pLicenseContext->fLoggedProtocolError))
|
|
{
|
|
LPTSTR ptszLogString[1] = { NULL };
|
|
|
|
if( pLicenseContext->ptszClientMachineName )
|
|
{
|
|
ptszLogString[0] = pLicenseContext->ptszClientMachineName;
|
|
}
|
|
|
|
// Couldn't renew/upgrade license
|
|
|
|
pLicenseContext->fLoggedProtocolError = TRUE;
|
|
|
|
if (pLicenseContext->pTsLicenseInfo->fTempLicense)
|
|
{
|
|
// The expired temporary license could not be upgraded
|
|
LicenseLogEvent(
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
EVENT_EXPIRED_TEMPORARY_LICENSE,
|
|
1,
|
|
ptszLogString
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// The expired permanent license could not be renewed
|
|
LicenseLogEvent(
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
EVENT_EXPIRED_PERMANENT_LICENSE,
|
|
1,
|
|
ptszLogString
|
|
);
|
|
}
|
|
}
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// The license has been validated successfully, generate the message to
|
|
// return to the client
|
|
//
|
|
|
|
Status = ConstructServerResponse( pLicenseContext->dwProtocolVersion,
|
|
LICENSE_RESPONSE_VALID_CLIENT,
|
|
pcbOutBuf,
|
|
ppOutBuf );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "HandleClientLicense: cannot pack error message: 0x%x\n", Status );
|
|
#endif
|
|
pLicenseContext->State = ABORTED;
|
|
Status = LICENSE_STATUS_SERVER_ABORT;
|
|
}
|
|
else
|
|
{
|
|
pLicenseContext->State = VALIDATED_LICENSE_COMPLETE;
|
|
}
|
|
|
|
done:
|
|
|
|
//
|
|
// free the memory used in the license info structure
|
|
//
|
|
|
|
FreeBinaryBlob( &LicenseInfo.EncryptedPreMasterSecret );
|
|
FreeBinaryBlob( &LicenseInfo.EncryptedHWID );
|
|
|
|
if( pLicenseContext->pbOldLicense != LicenseInfo.LicenseInfo.pBlob )
|
|
{
|
|
FreeBinaryBlob( &LicenseInfo.LicenseInfo );
|
|
}
|
|
|
|
if( pPreMasterSecret )
|
|
{
|
|
LicenseMemoryFree( &pPreMasterSecret );
|
|
}
|
|
|
|
return( Status);
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
HandleNewLicenseRequest(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
DWORD cbInBuf,
|
|
PBYTE pInBuf,
|
|
DWORD * pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
LICENSE_STATUS Status;
|
|
Hydra_Client_New_License_Request NewLicenseRequest;
|
|
PBYTE pPreMasterSecret = NULL;
|
|
DWORD dwPreMasterSecretLen = 0;
|
|
DWORD dwChallengeLen = 0;
|
|
DWORD CertType;
|
|
|
|
ASSERT( NULL != pInBuf );
|
|
ASSERT( cbInBuf > 0 );
|
|
|
|
if( ( NULL == pInBuf ) || ( 0 >= cbInBuf ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
InitBinaryBlob( &NewLicenseRequest.EncryptedPreMasterSecret );
|
|
|
|
//
|
|
// Unpack the new license request
|
|
//
|
|
|
|
Status = UnPackHydraClientNewLicenseRequest( pInBuf, cbInBuf, &NewLicenseRequest );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: HandleNewLicenseRequest: cannot unpack client request: 0x%x\n", Status );
|
|
#endif
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// save the client user and machine name
|
|
//
|
|
|
|
#ifdef UNICODE
|
|
|
|
//
|
|
// convert the client's user and machine name to unicode
|
|
//
|
|
|
|
if( ( NewLicenseRequest.ClientUserName.pBlob ) &&
|
|
( NULL == pLicenseContext->ptszClientUserName ) )
|
|
{
|
|
Status = Ascii2Wchar( NewLicenseRequest.ClientUserName.pBlob,
|
|
&pLicenseContext->ptszClientUserName );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: HandleNewLicenseRequest: cannot convert client user name: %s to wide char: 0x%x\n",
|
|
NewLicenseRequest.ClientUserName.pBlob, Status );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if( ( NewLicenseRequest.ClientMachineName.pBlob ) &&
|
|
( NULL == pLicenseContext->ptszClientMachineName ) )
|
|
{
|
|
Status = Ascii2Wchar( NewLicenseRequest.ClientMachineName.pBlob,
|
|
&pLicenseContext->ptszClientMachineName );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: HandleNewLicenseRequest: cannot convert client machine name %s to wide char: 0x%x\n",
|
|
NewLicenseRequest.ClientMachineName.pBlob, Status );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#else // non-UNICODE
|
|
|
|
//
|
|
// save the client's user and machine name
|
|
//
|
|
|
|
if( ( NewLicenseRequest.ClientUserName.pBlob ) &&
|
|
( NULL == pLicenseContext->ptszClientUserName ) )
|
|
{
|
|
Status = LicenseMemoryAllocate(
|
|
NewLicenseRequest.ClientUserName.wBlobLen,
|
|
&pLicenseContext->ptszClientUserName );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: HandleNewLicenseRequest: cannot allocate memory for client's user name: 0x%x\n",
|
|
Status );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
memcpy( pLicenseContext->ptszClientUserName,
|
|
NewLicenseRequest.ClientUserName.pBlob,
|
|
NewLicenseRequest.ClientUserName.wBlobLen );
|
|
}
|
|
}
|
|
|
|
if( ( NewLicenseRequest.ClientMachineName.pBlob ) &&
|
|
( NULL == pLicenseContext->ptszClientMachineName ) )
|
|
{
|
|
Status = LicenseMemoryAllocate(
|
|
NewLicenseRequest.ClientMachineName.wBlobLen,
|
|
&pLicenseContext->ptszClientMachineName );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: HandleNewLicenseRequest: cannot allocate memory for client's machine name: 0x%x\n",
|
|
Status );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
memcpy( pLicenseContext->ptszClientMachineName,
|
|
NewLicenseRequest.ClientMachineName.pBlob,
|
|
NewLicenseRequest.ClientMachineName.wBlobLen );
|
|
}
|
|
}
|
|
|
|
#endif // UNICODE
|
|
|
|
//
|
|
// Initialize the crypto context with the key exchange info and build the pre-master
|
|
// secret. We need the server and client random numbers and the pre-master secret
|
|
// to build the pre-master secret.
|
|
//
|
|
|
|
memcpy( pLicenseContext->CryptoContext.rgbClientRandom,
|
|
NewLicenseRequest.ClientRandom,
|
|
LICENSE_RANDOM );
|
|
|
|
pLicenseContext->CryptoContext.dwKeyExchAlg = NewLicenseRequest.dwPrefKeyExchangeAlg;
|
|
|
|
//
|
|
// Get the pre-master secret from the enveloped data
|
|
//
|
|
|
|
Status = GetEnvelopedData( pLicenseContext->CertTypeUsed,
|
|
NewLicenseRequest.EncryptedPreMasterSecret.pBlob,
|
|
( DWORD )NewLicenseRequest.EncryptedPreMasterSecret.wBlobLen,
|
|
&pPreMasterSecret,
|
|
&dwPreMasterSecretLen );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: HandleNewLicenseRequest: cannot get enveloped data: 0x%x", Status );
|
|
#endif
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// set the premaster secret and generate the master secret
|
|
//
|
|
|
|
Status = LicenseSetPreMasterSecret( &pLicenseContext->CryptoContext, pPreMasterSecret );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
Status = LicenseBuildMasterSecret( &pLicenseContext->CryptoContext );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Derive the session key from the key exchange info
|
|
//
|
|
|
|
Status = LicenseMakeSessionKeys( &pLicenseContext->CryptoContext, 0 );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// record the client platform ID and issue the platform challenge
|
|
//
|
|
|
|
pLicenseContext->dwClientPlatformID = NewLicenseRequest.dwPlatformID;
|
|
|
|
Status = IssuePlatformChallenge( pLicenseContext, pcbOutBuf, ppOutBuf );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// update our state
|
|
//
|
|
|
|
pLicenseContext->State = ISSUED_PLATFORM_CHALLENGE;
|
|
|
|
Status = LICENSE_STATUS_CONTINUE;
|
|
|
|
|
|
done:
|
|
|
|
FreeBinaryBlob( &NewLicenseRequest.EncryptedPreMasterSecret );
|
|
FreeBinaryBlob( &NewLicenseRequest.ClientUserName );
|
|
FreeBinaryBlob( &NewLicenseRequest.ClientMachineName );
|
|
|
|
if( pPreMasterSecret )
|
|
{
|
|
LicenseMemoryFree( &pPreMasterSecret );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
HandleClientError(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
DWORD cbInBuf,
|
|
PBYTE pInBuf,
|
|
DWORD * pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
LICENSE_STATUS Status;
|
|
License_Error_Message ClientError;
|
|
|
|
ASSERT( NULL != pInBuf );
|
|
ASSERT( cbInBuf > 0 );
|
|
|
|
if( ( NULL == pInBuf ) || ( 0 >= cbInBuf ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
InitBinaryBlob( &ClientError.bbErrorInfo );
|
|
|
|
//
|
|
// unpack the client error
|
|
//
|
|
|
|
Status = UnPackHydraClientErrorMessage( pInBuf, cbInBuf, &ClientError );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Process the client error code, the possible errors are:
|
|
// (1) Error processing the hydra server certificate
|
|
// (2) Client has no license and does not want one
|
|
//
|
|
// For now, just record the client error and abort the operation
|
|
//
|
|
|
|
pLicenseContext->dwClientError = ClientError.dwErrorCode;
|
|
pLicenseContext->State = ABORTED;
|
|
|
|
FreeBinaryBlob( &ClientError.bbErrorInfo );
|
|
|
|
return( LICENSE_STATUS_CLIENT_ABORT );
|
|
}
|
|
|
|
LICENSE_STATUS
|
|
AuthWithLicenseServer(
|
|
PHS_Protocol_Context pLicenseContext )
|
|
{
|
|
LICENSE_STATUS Status = LICENSE_STATUS_OK;
|
|
LPBYTE lpCert = NULL;
|
|
DWORD dwResult, RpcStatus;
|
|
DWORD dwSize;
|
|
|
|
if (pLicenseContext->hLSHandle == NULL)
|
|
return LICENSE_STATUS_INVALID_SERVER_CONTEXT;
|
|
|
|
Status = TLSGetTSCertificate(CERT_TYPE_X509, &lpCert, &dwSize);
|
|
|
|
if (Status != LICENSE_STATUS_OK)
|
|
{
|
|
Status = TLSGetTSCertificate(CERT_TYPE_PROPRIETORY, &lpCert, &dwSize);
|
|
}
|
|
|
|
if (Status != LICENSE_STATUS_OK)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
RpcStatus = TLSSendServerCertificate(
|
|
pLicenseContext->hLSHandle,
|
|
dwSize,
|
|
lpCert,
|
|
&dwResult
|
|
);
|
|
|
|
if( ( RPC_S_OK != RpcStatus ) || ( LSERVER_S_SUCCESS != dwResult ) )
|
|
{
|
|
Status = LICENSE_STATUS_AUTHENTICATION_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if (lpCert)
|
|
TLSFreeTSCertificate(lpCert);
|
|
|
|
return Status;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
CheckConnectLicenseServer(
|
|
PHS_Protocol_Context pLicenseContext )
|
|
{
|
|
LICENSE_STATUS Status = LICENSE_STATUS_NO_LICENSE_SERVER;
|
|
|
|
if (pLicenseContext->hLSHandle != NULL)
|
|
return LICENSE_STATUS_OK;
|
|
|
|
pLicenseContext->hLSHandle = TLSConnectToAnyLsServer(LS_DISCOVERY_TIMEOUT);
|
|
|
|
if (NULL != pLicenseContext->hLSHandle)
|
|
{
|
|
Status = AuthWithLicenseServer(pLicenseContext);
|
|
if (Status == LICENSE_STATUS_OK)
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BOOL fInDomain;
|
|
LPWSTR szDomain = NULL;
|
|
DWORD dwErr;
|
|
|
|
dwErr = TLSInDomain(&fInDomain,&szDomain);
|
|
|
|
if ((ERROR_SUCCESS == dwErr) && (NULL != szDomain))
|
|
{
|
|
ThrottleLicenseLogEvent(
|
|
EVENTLOG_WARNING_TYPE,
|
|
fInDomain
|
|
? EVENT_NO_LICENSE_SERVER_DOMAIN
|
|
: EVENT_NO_LICENSE_SERVER_WORKGROUP,
|
|
1,
|
|
&szDomain );
|
|
}
|
|
else
|
|
{
|
|
ThrottleLicenseLogEvent(
|
|
EVENTLOG_WARNING_TYPE,
|
|
EVENT_NO_LICENSE_SERVER,
|
|
0,
|
|
NULL );
|
|
}
|
|
|
|
if (NULL != szDomain)
|
|
{
|
|
NetApiBufferFree(szDomain);
|
|
}
|
|
}
|
|
|
|
// error case
|
|
if (NULL != pLicenseContext->hLSHandle)
|
|
{
|
|
TLSDisconnectFromServer(pLicenseContext->hLSHandle);
|
|
pLicenseContext->hLSHandle = NULL;
|
|
}
|
|
|
|
done:
|
|
return Status;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
CheckConnectNamedLicenseServer(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
TCHAR *tszComputerName)
|
|
{
|
|
LICENSE_STATUS Status = LICENSE_STATUS_OK;
|
|
|
|
if (pLicenseContext->hLSHandle != NULL)
|
|
return LICENSE_STATUS_OK;
|
|
|
|
pLicenseContext->hLSHandle = TLSConnectToLsServer(tszComputerName);
|
|
|
|
if (NULL == pLicenseContext->hLSHandle)
|
|
{
|
|
Status = LICENSE_STATUS_NO_LICENSE_SERVER;
|
|
goto done;
|
|
}
|
|
|
|
Status = AuthWithLicenseServer(pLicenseContext);
|
|
if (Status != LICENSE_STATUS_OK)
|
|
{
|
|
TLSDisconnectFromServer(pLicenseContext->hLSHandle);
|
|
pLicenseContext->hLSHandle = NULL;
|
|
}
|
|
|
|
done:
|
|
return Status;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
CheckUpgradeLicense(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
PDWORD pSupportFlags,
|
|
PLicense_Request pLicenseRequest,
|
|
DWORD cbChallengeResponse,
|
|
PBYTE pbChallengeResponse,
|
|
PHWID pHwid,
|
|
PDWORD pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
LICENSE_STATUS
|
|
Status = LICENSE_STATUS_OK;
|
|
DWORD
|
|
cbLicense = 0;
|
|
PBYTE
|
|
pbLicense = NULL;
|
|
Validation_Info
|
|
ValidationInfo;
|
|
DWORD
|
|
dwLicenseState = 0;
|
|
DWORD
|
|
RpcStatus, LsStatus;
|
|
BOOL
|
|
fRetried = FALSE;
|
|
|
|
reconnect:
|
|
Status = CheckConnectLicenseServer(pLicenseContext);
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
RpcStatus = TLSUpgradeLicenseEx(pLicenseContext->hLSHandle,
|
|
pSupportFlags,
|
|
pLicenseRequest,
|
|
0, // ChallengeContext unused
|
|
cbChallengeResponse,
|
|
pbChallengeResponse,
|
|
pLicenseContext->cbOldLicense,
|
|
pLicenseContext->pbOldLicense,
|
|
1, // dwQuantity
|
|
&cbLicense,
|
|
&pbLicense,
|
|
&LsStatus
|
|
);
|
|
|
|
if ( RPC_S_OK != RpcStatus )
|
|
{
|
|
if (!fRetried)
|
|
{
|
|
fRetried = TRUE;
|
|
pLicenseContext->hLSHandle = NULL;
|
|
goto reconnect;
|
|
}
|
|
else
|
|
{
|
|
Status = LICENSE_STATUS_NO_LICENSE_SERVER;
|
|
}
|
|
}
|
|
else if ( LSERVER_ERROR_BASE <= LsStatus )
|
|
{
|
|
Status = LsStatusToLicenseStatus(LsStatus,
|
|
LICENSE_STATUS_CANNOT_UPGRADE_LICENSE);
|
|
}
|
|
|
|
ValidationInfo.pValidationData = ( PBYTE )pHwid;
|
|
ValidationInfo.cbValidationData = LICENSE_HWID_LENGTH;
|
|
ValidationInfo.pProductInfo = &pLicenseContext->ProductInfo;
|
|
|
|
//
|
|
// if we cannot upgrade the license, check if the current license is
|
|
// still good. If it is, return it to the client.
|
|
//
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
LICENSE_STATUS
|
|
LicenseStatus;
|
|
|
|
ValidationInfo.pLicense = pLicenseContext->pbOldLicense;
|
|
ValidationInfo.cbLicense = pLicenseContext->cbOldLicense;
|
|
|
|
LicenseStatus = ValidateLicense(
|
|
pLicenseContext,
|
|
&ValidationInfo,
|
|
&dwLicenseState,
|
|
FALSE // fCheckForPermanent
|
|
);
|
|
|
|
if( ( LICENSE_STATUS_OK == LicenseStatus ) ||
|
|
( LICENSE_STATUS_SHOULD_UPGRADE_LICENSE == LicenseStatus ) )
|
|
{
|
|
//
|
|
// Store the raw license bits for later use. Ignore failure;
|
|
// that only means that if this is a license that should be
|
|
// marked, termsrv won't be able to.
|
|
//
|
|
|
|
CacheRawLicenseData(pLicenseContext,
|
|
pLicenseContext->pbOldLicense,
|
|
pLicenseContext->cbOldLicense);
|
|
|
|
//
|
|
// The current license is still OK, send it back to the client.
|
|
//
|
|
|
|
Status = PackageLicense(
|
|
pLicenseContext,
|
|
pLicenseContext->cbOldLicense,
|
|
pLicenseContext->pbOldLicense,
|
|
pcbOutBuf,
|
|
ppOutBuf,
|
|
FALSE );
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The current license is not good any more
|
|
//
|
|
|
|
#if DBG
|
|
DbgPrint( "UpgradeLicense: cannot upgrade license 0x%x\n", Status );
|
|
#endif
|
|
|
|
}
|
|
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// the license upgrade was successful. Now validate the new license so
|
|
// that the new license info will be cached.
|
|
//
|
|
|
|
ValidationInfo.pLicense = pbLicense;
|
|
ValidationInfo.cbLicense = cbLicense;
|
|
|
|
ValidateLicense(
|
|
pLicenseContext,
|
|
&ValidationInfo,
|
|
&dwLicenseState,
|
|
TRUE // fCheckForPermanent
|
|
);
|
|
|
|
//
|
|
// Store the raw license bits for later use. Ignore failure; that only
|
|
// means that if this is a license that should be marked, termsrv won't be
|
|
// able to.
|
|
//
|
|
|
|
CacheRawLicenseData(pLicenseContext,
|
|
pLicenseContext->pbOldLicense,
|
|
pLicenseContext->cbOldLicense);
|
|
|
|
//
|
|
// pack up the upgraded license
|
|
//
|
|
|
|
Status = PackageLicense( pLicenseContext,
|
|
cbLicense,
|
|
pbLicense,
|
|
pcbOutBuf,
|
|
ppOutBuf,
|
|
FALSE );
|
|
|
|
done:
|
|
|
|
if( pbLicense )
|
|
{
|
|
LicenseMemoryFree( &pbLicense );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
HandlePlatformChallengeResponse(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
DWORD cbInBuf,
|
|
PBYTE pInBuf,
|
|
DWORD * pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
LICENSE_STATUS Status;
|
|
Hydra_Client_Platform_Challenge_Response PlatformChallengeResponse;
|
|
BYTE ChallengeResponse[PLATFORM_CHALLENGE_LENGTH];
|
|
PBYTE pLicense = NULL;
|
|
DWORD cbLicenseSize = 0;
|
|
License_Request LicenseRequest;
|
|
HS_LICENSE_STATE HsState = ABORTED;
|
|
License_Requester_Info RequesterInfo;
|
|
BYTE bEncryptedHwid[ sizeof( HWID ) ];
|
|
PBYTE pbSecretKey = NULL;
|
|
DWORD cbMacData = 0, cbSecretKey = 0, cbEncryptedHwid = sizeof( HWID );
|
|
BYTE MacData[ sizeof( HWID ) + PLATFORM_CHALLENGE_LENGTH ];
|
|
BYTE ComputedMac[LICENSE_MAC_DATA];
|
|
HWID Hwid;
|
|
DWORD RpcStatus,LsStatus;
|
|
TCHAR tszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
TCHAR tszUserName[UNLEN + 1];
|
|
DWORD dwComputerName = MAX_COMPUTERNAME_LENGTH + 1;
|
|
DWORD dwUserName = UNLEN + 1;
|
|
DWORD dwSupportFlags = ALL_KNOWN_SUPPORT_FLAGS;
|
|
BOOL fRetried = FALSE;
|
|
|
|
ASSERT( NULL != pInBuf );
|
|
ASSERT( cbInBuf > 0 );
|
|
|
|
if( ( NULL == pInBuf ) || ( 0 >= cbInBuf ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
//
|
|
// unpack the platform challenge response
|
|
//
|
|
|
|
InitBinaryBlob( &PlatformChallengeResponse.EncryptedChallengeResponse );
|
|
InitBinaryBlob( &PlatformChallengeResponse.EncryptedHWID );
|
|
|
|
Status = UnPackHydraClientPlatformChallengeResponse( pInBuf, cbInBuf, &PlatformChallengeResponse );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// decrypt the encrypted challenge response and HWID
|
|
//
|
|
|
|
ASSERT(PlatformChallengeResponse.EncryptedChallengeResponse.wBlobLen
|
|
<= PLATFORM_CHALLENGE_LENGTH);
|
|
|
|
memcpy( ChallengeResponse,
|
|
PlatformChallengeResponse.EncryptedChallengeResponse.pBlob,
|
|
PlatformChallengeResponse.EncryptedChallengeResponse.wBlobLen );
|
|
|
|
Status = LicenseDecryptSessionData( &pLicenseContext->CryptoContext,
|
|
ChallengeResponse,
|
|
( DWORD )PlatformChallengeResponse.EncryptedChallengeResponse.wBlobLen );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// decrypt the client's HWID
|
|
//
|
|
|
|
if( PlatformChallengeResponse.EncryptedHWID.wBlobLen > sizeof(Hwid) )
|
|
{
|
|
Status = LICENSE_STATUS_INVALID_MAC_DATA;
|
|
goto done;
|
|
}
|
|
|
|
memcpy( &Hwid,
|
|
PlatformChallengeResponse.EncryptedHWID.pBlob,
|
|
PlatformChallengeResponse.EncryptedHWID.wBlobLen );
|
|
|
|
Status = LicenseDecryptSessionData( &pLicenseContext->CryptoContext,
|
|
( PBYTE )&Hwid,
|
|
( DWORD )PlatformChallengeResponse.EncryptedHWID.wBlobLen );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Verify the MAC data on the decrypted challenge response and the HWID
|
|
//
|
|
|
|
cbMacData += ( DWORD )PlatformChallengeResponse.EncryptedChallengeResponse.wBlobLen;
|
|
|
|
memcpy( MacData,
|
|
ChallengeResponse,
|
|
( DWORD )PlatformChallengeResponse.EncryptedChallengeResponse.wBlobLen );
|
|
|
|
cbMacData += ( DWORD )PlatformChallengeResponse.EncryptedHWID.wBlobLen;
|
|
|
|
memcpy( MacData + ( DWORD )PlatformChallengeResponse.EncryptedChallengeResponse.wBlobLen,
|
|
&Hwid,
|
|
( DWORD )PlatformChallengeResponse.EncryptedHWID.wBlobLen );
|
|
|
|
Status = LicenseGenerateMAC( &pLicenseContext->CryptoContext,
|
|
MacData,
|
|
cbMacData,
|
|
ComputedMac );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
Status = LICENSE_STATUS_INVALID_MAC_DATA;
|
|
goto done;
|
|
}
|
|
|
|
if( 0 != memcmp( ComputedMac,
|
|
PlatformChallengeResponse.MACData,
|
|
LICENSE_MAC_DATA ) )
|
|
{
|
|
Status = LICENSE_STATUS_INVALID_MAC_DATA;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// now get the license server's secret key and encrypt the HWID before transmitting it.
|
|
//
|
|
|
|
LicenseGetSecretKey( &cbSecretKey, NULL );
|
|
|
|
Status = LicenseMemoryAllocate( cbSecretKey, &pbSecretKey );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
Status = LicenseGetSecretKey( &cbSecretKey, pbSecretKey );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
Status = LicenseEncryptHwid( &Hwid, &cbEncryptedHwid, bEncryptedHwid,
|
|
cbSecretKey, pbSecretKey );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
LicenseRequest.cbEncryptedHwid = cbEncryptedHwid;
|
|
LicenseRequest.pbEncryptedHwid = bEncryptedHwid;
|
|
|
|
//
|
|
// send the platform challenge response to the license manager and wait for it
|
|
// to issue a new license.
|
|
//
|
|
|
|
LicenseRequest.pProductInfo = &pLicenseContext->ProductInfo;
|
|
|
|
LicenseRequest.dwPlatformID = pLicenseContext->dwClientPlatformID;
|
|
LicenseRequest.dwLanguageID = GetSystemDefaultLCID();
|
|
|
|
//
|
|
// if we don't have the client's user and machine name, get it now.
|
|
//
|
|
|
|
if( NULL == pLicenseContext->ptszClientMachineName )
|
|
{
|
|
//
|
|
// if we don't have the client machine name, just use the
|
|
// hydra server machine name
|
|
//
|
|
|
|
if( !GetComputerName( tszComputerName, &dwComputerName ) )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "HandlePlatformChallengeResponse: cannot get computer name: 0x%x\n", GetLastError() );
|
|
#endif
|
|
memset( tszComputerName, 0, ( MAX_COMPUTERNAME_LENGTH + 1 ) * sizeof( TCHAR ) );
|
|
}
|
|
|
|
RequesterInfo.ptszMachineName = tszComputerName;
|
|
}
|
|
else
|
|
{
|
|
RequesterInfo.ptszMachineName = pLicenseContext->ptszClientMachineName;
|
|
}
|
|
|
|
if( NULL == pLicenseContext->ptszClientUserName )
|
|
{
|
|
//
|
|
// if we don't have the client's user name, just use the
|
|
// hydra server logged on user name.
|
|
//
|
|
|
|
if( !GetUserName( tszUserName, &dwUserName ) )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "HandlePlatformChallengeResponse: cannot get user name: 0x%x\n", GetLastError() );
|
|
#endif
|
|
memset( tszUserName, 0, ( UNLEN + 1 ) * sizeof( TCHAR ) );
|
|
}
|
|
|
|
RequesterInfo.ptszUserName = tszUserName;
|
|
}
|
|
else
|
|
{
|
|
RequesterInfo.ptszUserName = pLicenseContext->ptszClientUserName;
|
|
}
|
|
|
|
if( pLicenseContext->pbOldLicense )
|
|
{
|
|
//
|
|
// attempt to upgrade an old license
|
|
//
|
|
|
|
Status = CheckUpgradeLicense(
|
|
pLicenseContext,
|
|
&dwSupportFlags,
|
|
&LicenseRequest,
|
|
( DWORD )PlatformChallengeResponse.EncryptedChallengeResponse.wBlobLen,
|
|
ChallengeResponse,
|
|
&Hwid,
|
|
pcbOutBuf,
|
|
ppOutBuf );
|
|
|
|
if ((NULL != pLicenseContext->pTsLicenseInfo)
|
|
&& (LICENSE_STATUS_OK != Status))
|
|
{
|
|
pLicenseContext->fLoggedProtocolError = TRUE;
|
|
|
|
if (pLicenseContext->pTsLicenseInfo->fTempLicense)
|
|
{
|
|
// The expired temporary license could not be upgraded
|
|
LicenseLogEvent(
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
EVENT_EXPIRED_TEMPORARY_LICENSE,
|
|
1,
|
|
&(RequesterInfo.ptszMachineName)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// The expired permanent license could not be renewed
|
|
LicenseLogEvent(
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
EVENT_EXPIRED_PERMANENT_LICENSE,
|
|
1,
|
|
&(RequesterInfo.ptszMachineName)
|
|
);
|
|
}
|
|
}
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
reconnect:
|
|
|
|
Status = CheckConnectLicenseServer(pLicenseContext);
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
RpcStatus = TLSIssueNewLicenseEx(
|
|
pLicenseContext->hLSHandle,
|
|
&dwSupportFlags,
|
|
0, // ChallengeContext unused
|
|
&LicenseRequest,
|
|
RequesterInfo.ptszMachineName,
|
|
RequesterInfo.ptszUserName,
|
|
( DWORD )PlatformChallengeResponse.EncryptedChallengeResponse.wBlobLen,
|
|
ChallengeResponse,
|
|
TRUE,
|
|
1, // dwQuantity
|
|
&cbLicenseSize,
|
|
&pLicense,
|
|
&LsStatus );
|
|
|
|
if ( RPC_S_OK != RpcStatus )
|
|
{
|
|
if (!fRetried)
|
|
{
|
|
fRetried = TRUE;
|
|
pLicenseContext->hLSHandle = NULL;
|
|
goto reconnect;
|
|
}
|
|
else
|
|
{
|
|
Status = LICENSE_STATUS_NO_LICENSE_SERVER;
|
|
}
|
|
}
|
|
else if ( LSERVER_ERROR_BASE <= LsStatus )
|
|
{
|
|
Status = LsStatusToLicenseStatus(LsStatus,
|
|
LICENSE_STATUS_NO_LICENSE_ERROR);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwLicenseState;
|
|
Validation_Info ValidationInfo;
|
|
|
|
//
|
|
// Validate the license for the sole purpose of caching the
|
|
// information.
|
|
//
|
|
|
|
ValidationInfo.pValidationData = ( PBYTE )&Hwid;
|
|
ValidationInfo.cbValidationData = LICENSE_HWID_LENGTH;
|
|
ValidationInfo.pProductInfo = &pLicenseContext->ProductInfo;
|
|
ValidationInfo.pLicense = pLicense;
|
|
ValidationInfo.cbLicense = cbLicenseSize;
|
|
|
|
ValidateLicense(pLicenseContext,
|
|
&ValidationInfo,
|
|
&dwLicenseState,
|
|
TRUE // fCheckForPermanent
|
|
);
|
|
|
|
//
|
|
// Store the raw license bits for later use. Ignore failure;
|
|
// that only means that if this is a license that should be
|
|
// marked, termsrv won't be able to.
|
|
//
|
|
|
|
CacheRawLicenseData(pLicenseContext, pLicense, cbLicenseSize);
|
|
|
|
//
|
|
// package up the new license
|
|
//
|
|
|
|
Status = PackageLicense( pLicenseContext,
|
|
cbLicenseSize,
|
|
pLicense,
|
|
pcbOutBuf,
|
|
ppOutBuf,
|
|
TRUE );
|
|
}
|
|
}
|
|
|
|
SetExtendedData(pLicenseContext, dwSupportFlags);
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// done with the protocol
|
|
//
|
|
|
|
HsState = ISSUED_LICENSE_COMPLETE;
|
|
Status = LICENSE_STATUS_ISSUED_LICENSE;
|
|
|
|
done:
|
|
|
|
//
|
|
// log all issue license failures
|
|
//
|
|
|
|
if( (LICENSE_STATUS_ISSUED_LICENSE != Status)
|
|
&& (pLicenseContext != NULL)
|
|
&& (!pLicenseContext->fLoggedProtocolError) )
|
|
{
|
|
pLicenseContext->fLoggedProtocolError = TRUE;
|
|
|
|
LicenseLogEvent( EVENTLOG_INFORMATION_TYPE,
|
|
EVENT_CANNOT_ISSUE_LICENSE,
|
|
0, NULL );
|
|
}
|
|
|
|
if( pLicense )
|
|
{
|
|
LicenseMemoryFree( &pLicense );
|
|
}
|
|
|
|
if( pbSecretKey )
|
|
{
|
|
LicenseMemoryFree( &pbSecretKey );
|
|
}
|
|
|
|
if( pLicenseContext->pbOldLicense )
|
|
{
|
|
//
|
|
// free the old license
|
|
//
|
|
|
|
LicenseMemoryFree( &pLicenseContext->pbOldLicense );
|
|
pLicenseContext->cbOldLicense = 0;
|
|
}
|
|
|
|
FreeBinaryBlob( &PlatformChallengeResponse.EncryptedChallengeResponse );
|
|
FreeBinaryBlob( &PlatformChallengeResponse.EncryptedHWID );
|
|
|
|
pLicenseContext->State = HsState;
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
IssuePlatformChallenge(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
PDWORD pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
Hydra_Server_Platform_Challenge
|
|
PlatformChallenge;
|
|
DWORD
|
|
dwChallengeLen;
|
|
LPBYTE
|
|
pbChallengeData = NULL;
|
|
LICENSE_STATUS
|
|
Status = LICENSE_STATUS_OK;
|
|
DWORD
|
|
RpcStatus,LsStatus;
|
|
CHALLENGE_CONTEXT
|
|
ChallengeContext;
|
|
|
|
//
|
|
// generate the platform challenge
|
|
//
|
|
|
|
ASSERT( pLicenseContext );
|
|
|
|
Status = CheckConnectLicenseServer(pLicenseContext);
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
RpcStatus = TLSIssuePlatformChallenge(pLicenseContext->hLSHandle,
|
|
pLicenseContext->dwClientPlatformID,
|
|
&ChallengeContext, // Context is unused by server, but we need a non-null pointer
|
|
&dwChallengeLen,
|
|
&pbChallengeData,
|
|
&LsStatus);
|
|
|
|
if(( RPC_S_OK != RpcStatus ) || ( LSERVER_ERROR_BASE <= LsStatus ) )
|
|
{
|
|
Status = LICENSE_STATUS_NO_PLATFORM_CHALLENGE ;
|
|
#if DBG
|
|
DbgPrint( "LICPROT: cannot issue platform challenge: 0x%x\n", Status );
|
|
#endif
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Form the platform challenge message
|
|
//
|
|
|
|
PlatformChallenge.EncryptedPlatformChallenge.wBlobLen = ( WORD )dwChallengeLen;
|
|
PlatformChallenge.EncryptedPlatformChallenge.pBlob = pbChallengeData;
|
|
|
|
//
|
|
// calculate the MAC for the unencrypted platform challenge
|
|
//
|
|
|
|
Status = LicenseGenerateMAC( &pLicenseContext->CryptoContext,
|
|
PlatformChallenge.EncryptedPlatformChallenge.pBlob,
|
|
( DWORD )PlatformChallenge.EncryptedPlatformChallenge.wBlobLen,
|
|
PlatformChallenge.MACData );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: cannot generate MAC data for challenge platform: 0x%x\n", Status );
|
|
#endif
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// encrypt the platform challenge
|
|
//
|
|
|
|
Status = LicenseEncryptSessionData( &pLicenseContext->CryptoContext,
|
|
PlatformChallenge.EncryptedPlatformChallenge.pBlob,
|
|
PlatformChallenge.EncryptedPlatformChallenge.wBlobLen );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: cannot encrypt platform challenge data: 0x%x\n", Status );
|
|
#endif
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// pack the platform challenge
|
|
//
|
|
|
|
Status = PackHydraServerPlatformChallenge(
|
|
pLicenseContext->dwProtocolVersion,
|
|
&PlatformChallenge,
|
|
ppOutBuf,
|
|
pcbOutBuf );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: cannot pack platform challenge data: 0x%x\n", Status );
|
|
#endif
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
|
|
if( pbChallengeData )
|
|
{
|
|
LicenseMemoryFree( &pbChallengeData );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
PackageLicense(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
DWORD cbLicense,
|
|
PBYTE pLicense,
|
|
PDWORD pcbOutBuf,
|
|
PBYTE * ppOutBuf,
|
|
BOOL fNewLicense )
|
|
{
|
|
LICENSE_STATUS Status;
|
|
New_License_Info NewLicenseInfo;
|
|
Hydra_Server_New_License NewLicense;
|
|
DWORD cbEncryptedLicenseInfo = 0;
|
|
|
|
if( ( 0 == cbLicense ) || ( NULL == pLicense ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
//
|
|
// Initialize the new license information
|
|
//
|
|
|
|
NewLicenseInfo.dwVersion = pLicenseContext->ProductInfo.dwVersion;
|
|
|
|
NewLicenseInfo.cbScope = strlen( pLicenseContext->Scope ) + 1;
|
|
NewLicenseInfo.pbScope = pLicenseContext->Scope;
|
|
|
|
NewLicenseInfo.cbCompanyName = pLicenseContext->ProductInfo.cbCompanyName;
|
|
NewLicenseInfo.pbCompanyName = pLicenseContext->ProductInfo.pbCompanyName;
|
|
|
|
NewLicenseInfo.cbProductID = pLicenseContext->ProductInfo.cbProductID;
|
|
NewLicenseInfo.pbProductID = pLicenseContext->ProductInfo.pbProductID;
|
|
|
|
NewLicenseInfo.cbLicenseInfo = cbLicense;
|
|
NewLicenseInfo.pbLicenseInfo = pLicense;
|
|
|
|
//
|
|
// initialize the blob that will contain the encrypted new license
|
|
// information
|
|
//
|
|
|
|
NewLicense.EncryptedNewLicenseInfo.wBlobLen = 0;
|
|
NewLicense.EncryptedNewLicenseInfo.pBlob = NULL;
|
|
|
|
//
|
|
// pack the new license information
|
|
//
|
|
|
|
Status = PackNewLicenseInfo( &NewLicenseInfo,
|
|
&NewLicense.EncryptedNewLicenseInfo.pBlob,
|
|
&cbEncryptedLicenseInfo );
|
|
|
|
NewLicense.EncryptedNewLicenseInfo.wBlobLen = ( WORD )cbEncryptedLicenseInfo;
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// calculate the mac data
|
|
//
|
|
|
|
Status = LicenseGenerateMAC( &pLicenseContext->CryptoContext,
|
|
NewLicense.EncryptedNewLicenseInfo.pBlob,
|
|
( DWORD )NewLicense.EncryptedNewLicenseInfo.wBlobLen,
|
|
NewLicense.MACData );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
|
|
//
|
|
// Encrypt the new license info
|
|
//
|
|
|
|
Status = LicenseEncryptSessionData( &pLicenseContext->CryptoContext,
|
|
NewLicense.EncryptedNewLicenseInfo.pBlob,
|
|
cbEncryptedLicenseInfo );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// package up the license for the client
|
|
//
|
|
|
|
if( fNewLicense )
|
|
{
|
|
Status = PackHydraServerNewLicense(
|
|
pLicenseContext->dwProtocolVersion,
|
|
&NewLicense,
|
|
ppOutBuf,
|
|
pcbOutBuf );
|
|
}
|
|
else
|
|
{
|
|
Status = PackHydraServerUpgradeLicense(
|
|
pLicenseContext->dwProtocolVersion,
|
|
&NewLicense,
|
|
ppOutBuf,
|
|
pcbOutBuf );
|
|
}
|
|
|
|
done:
|
|
|
|
if( NewLicense.EncryptedNewLicenseInfo.pBlob )
|
|
{
|
|
LicenseMemoryFree( &NewLicense.EncryptedNewLicenseInfo.pBlob );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
ConstructProtocolResponse(
|
|
HANDLE hLicense,
|
|
DWORD dwResponse,
|
|
PDWORD pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
PHS_Protocol_Context
|
|
pLicenseContext;
|
|
LICENSE_STATUS
|
|
Status;
|
|
|
|
pLicenseContext = ( PHS_Protocol_Context )hLicense;
|
|
|
|
if (pLicenseContext == NULL)
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
LOCK( &pLicenseContext->CritSec );
|
|
|
|
//
|
|
// construct the server response. If this is a per seat license context, use the
|
|
// licensing protocol version specified in the context. Otherwise, use the
|
|
// protocol version that is compatible with Terminal server 4.0.
|
|
//
|
|
|
|
Status = ConstructServerResponse(
|
|
pLicenseContext->dwProtocolVersion,
|
|
dwResponse,
|
|
pcbOutBuf,
|
|
ppOutBuf );
|
|
|
|
UNLOCK( &pLicenseContext->CritSec );
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
ConstructServerResponse(
|
|
DWORD dwProtocolVersion,
|
|
DWORD dwResponse,
|
|
PDWORD pcbOutBuf,
|
|
PBYTE * ppOutBuf )
|
|
{
|
|
License_Error_Message ErrorMsg;
|
|
LICENSE_STATUS Status;
|
|
|
|
if( ( NULL == pcbOutBuf ) || ( NULL == ppOutBuf ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
if( LICENSE_RESPONSE_VALID_CLIENT == dwResponse )
|
|
{
|
|
ErrorMsg.dwErrorCode = GM_HS_ERR_VALID_CLIENT;
|
|
ErrorMsg.dwStateTransition = ST_NO_TRANSITION;
|
|
}
|
|
else if( LICENSE_RESPONSE_INVALID_CLIENT == dwResponse )
|
|
{
|
|
ErrorMsg.dwErrorCode = GM_HS_ERR_INVALID_CLIENT;
|
|
ErrorMsg.dwStateTransition = ST_TOTAL_ABORT;
|
|
}
|
|
else
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
ErrorMsg.bbErrorInfo.wBlobLen = 0;
|
|
ErrorMsg.bbErrorInfo.pBlob = NULL;
|
|
|
|
Status = PackHydraServerErrorMessage(
|
|
dwProtocolVersion,
|
|
&ErrorMsg,
|
|
ppOutBuf,
|
|
pcbOutBuf );
|
|
|
|
return( Status );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
GetHydraServerPrivateKey(
|
|
CERT_TYPE CertType,
|
|
PBYTE * ppPrivateKey,
|
|
PDWORD pcbPrivateKey )
|
|
{
|
|
#ifndef USE_HARDCODED
|
|
|
|
LICENSE_STATUS Status = LICENSE_STATUS_OK;
|
|
HANDLE hPrivateKeyFile = NULL;
|
|
DWORD dwFileSizeHigh, dwFileSizeLow;
|
|
WCHAR szPrivateKeyFile[MAX_PATH];
|
|
|
|
//
|
|
// form the path to the private key file
|
|
//
|
|
|
|
GetSystemDirectory( ( LPTSTR )szPrivateKeyFile, MAX_PATH );
|
|
wcscat( szPrivateKeyFile, L"\\" );
|
|
wcscat( szPrivateKeyFile, HYDRA_SERVER_PRIVATE_KEY_FILE );
|
|
|
|
//
|
|
// get the private key of the hydra server.
|
|
// For now, get the private key from a file.
|
|
//
|
|
|
|
hPrivateKeyFile = CreateFile( szPrivateKeyFile,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if( INVALID_HANDLE_VALUE == hPrivateKeyFile )
|
|
{
|
|
Status = LICENSE_STATUS_NO_PRIVATE_KEY;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// get the private key file size. We're counting on the private key file
|
|
// not to exceed 64K
|
|
//
|
|
|
|
dwFileSizeLow = GetFileSize( hPrivateKeyFile, &dwFileSizeHigh );
|
|
|
|
if( 0xFFFFFFFF == dwFileSizeLow )
|
|
{
|
|
Status = LICENSE_STATUS_NO_PRIVATE_KEY;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// allocate memory for the certificate and read the private key from the file.
|
|
//
|
|
|
|
*ppPrivateKey = NULL;
|
|
Status = LicenseMemoryAllocate( dwFileSizeLow, ppPrivateKey );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
Status = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
goto done;
|
|
}
|
|
|
|
if( 0 > ReadFile( hPrivateKeyFile,
|
|
*ppPrivateKey,
|
|
dwFileSizeLow,
|
|
pcbPrivateKey,
|
|
NULL ) )
|
|
{
|
|
if( *ppPrivateKey )
|
|
{
|
|
LicenseMemoryFree( ppPrivateKey );
|
|
}
|
|
|
|
Status = LICENSE_STATUS_NO_PRIVATE_KEY;
|
|
}
|
|
|
|
done:
|
|
|
|
if( hPrivateKeyFile )
|
|
{
|
|
CloseHandle( hPrivateKeyFile );
|
|
}
|
|
|
|
return( Status );
|
|
|
|
#else
|
|
|
|
LICENSE_STATUS Status;
|
|
DWORD dwSize;
|
|
LSCSPINFO CspData;
|
|
|
|
//
|
|
// Get the private key for the certificate that we are using
|
|
//
|
|
|
|
if( CERT_TYPE_PROPRIETORY == CertType )
|
|
{
|
|
CspData = LsCspInfo_PrivateKey;
|
|
}
|
|
else if( CERT_TYPE_X509 == CertType )
|
|
{
|
|
CspData = LsCspInfo_X509CertPrivateKey;
|
|
}
|
|
else
|
|
{
|
|
return( LICENSE_STATUS_NO_PRIVATE_KEY );
|
|
}
|
|
|
|
//
|
|
// call the Lscsp library to obtain the private key
|
|
//
|
|
|
|
if( LsCsp_GetServerData( CspData, NULL, &dwSize ) != LICENSE_STATUS_OK )
|
|
{
|
|
return( LICENSE_STATUS_NO_PRIVATE_KEY );
|
|
}
|
|
|
|
Status = LicenseMemoryAllocate( dwSize, ppPrivateKey );
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
return( Status );
|
|
}
|
|
|
|
if( LsCsp_GetServerData( CspData, *ppPrivateKey, &dwSize )
|
|
!= LICENSE_STATUS_OK )
|
|
{
|
|
LicenseMemoryFree( ppPrivateKey );
|
|
return( LICENSE_STATUS_INSUFFICIENT_BUFFER );
|
|
}
|
|
|
|
*pcbPrivateKey = dwSize;
|
|
|
|
return( LICENSE_STATUS_OK );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
GetEnvelopedData(
|
|
CERT_TYPE CertType,
|
|
PBYTE pEnvelopedData,
|
|
DWORD dwEnvelopedDataLen,
|
|
PBYTE * ppData,
|
|
PDWORD pdwDataLen )
|
|
{
|
|
LICENSE_STATUS
|
|
Status;
|
|
|
|
LsCsp_DecryptEnvelopedData(
|
|
CertType,
|
|
pEnvelopedData,
|
|
dwEnvelopedDataLen,
|
|
NULL,
|
|
pdwDataLen );
|
|
|
|
Status = LicenseMemoryAllocate( *pdwDataLen, ppData );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
if( !LsCsp_DecryptEnvelopedData(
|
|
CertType,
|
|
pEnvelopedData,
|
|
dwEnvelopedDataLen,
|
|
*ppData,
|
|
pdwDataLen ) )
|
|
{
|
|
Status = LICENSE_STATUS_INVALID_INPUT;
|
|
}
|
|
|
|
done:
|
|
|
|
return( Status );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
InitProductInfo(
|
|
PProduct_Info pProductInfo,
|
|
LPTSTR lptszProductSku )
|
|
{
|
|
LICENSE_STATUS Status;
|
|
|
|
pProductInfo->pbCompanyName = NULL;
|
|
pProductInfo->pbProductID = NULL;
|
|
|
|
pProductInfo->dwVersion = g_dwTerminalServerVersion;
|
|
|
|
pProductInfo->cbCompanyName = wcslen( PRODUCT_INFO_COMPANY_NAME ) * sizeof( WCHAR )
|
|
+ sizeof( WCHAR );
|
|
|
|
Status = LicenseMemoryAllocate( pProductInfo->cbCompanyName,
|
|
&pProductInfo->pbCompanyName );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "InitProductInfo: cannot allocate memory: 0x%x\n", Status );
|
|
#endif
|
|
goto error;
|
|
}
|
|
|
|
wcscpy( ( PWCHAR )pProductInfo->pbCompanyName, PRODUCT_INFO_COMPANY_NAME );
|
|
|
|
pProductInfo->cbProductID = _tcslen( lptszProductSku ) * sizeof( TCHAR )
|
|
+ sizeof( TCHAR );
|
|
|
|
Status = LicenseMemoryAllocate( pProductInfo->cbProductID,
|
|
&pProductInfo->pbProductID );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "InitProductInfo: cannot allocate memory: 0x%x\n", Status );
|
|
#endif
|
|
goto error;
|
|
}
|
|
|
|
_tcscpy( ( PTCHAR )pProductInfo->pbProductID, lptszProductSku );
|
|
|
|
return( Status );
|
|
|
|
error:
|
|
|
|
//
|
|
// error return, free allocated resources
|
|
//
|
|
|
|
if( pProductInfo->pbCompanyName )
|
|
{
|
|
LicenseMemoryFree( &pProductInfo->pbCompanyName );
|
|
}
|
|
|
|
if( pProductInfo->pbProductID )
|
|
{
|
|
LicenseMemoryFree( &pProductInfo->pbProductID );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
#define THROTTLE_WRAPAROUND 100
|
|
|
|
//
|
|
// Reduce the frequency of logging
|
|
// No need to strictly limit it to once every 100 calls
|
|
//
|
|
|
|
void
|
|
ThrottleLicenseLogEvent(
|
|
WORD wEventType,
|
|
DWORD dwEventId,
|
|
WORD cStrings,
|
|
PWCHAR * apwszStrings )
|
|
{
|
|
static LONG lLogged = THROTTLE_WRAPAROUND;
|
|
LONG lResult;
|
|
|
|
lResult = InterlockedIncrement(&lLogged);
|
|
|
|
if (THROTTLE_WRAPAROUND <= lResult)
|
|
{
|
|
LicenseLogEvent(
|
|
wEventType,
|
|
dwEventId,
|
|
cStrings,
|
|
apwszStrings );
|
|
|
|
lLogged = 0;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
LicenseLogEvent(
|
|
WORD wEventType,
|
|
DWORD dwEventId,
|
|
WORD cStrings,
|
|
PWCHAR * apwszStrings )
|
|
{
|
|
if (!g_fEventLogOpen)
|
|
{
|
|
LOCK(&g_EventLogCritSec);
|
|
|
|
if (!g_fEventLogOpen)
|
|
{
|
|
g_hEventLog = RegisterEventSource( NULL,
|
|
TERMINAL_SERVICE_EVENT_LOG );
|
|
|
|
if (NULL != g_hEventLog)
|
|
{
|
|
g_fEventLogOpen = TRUE;
|
|
}
|
|
}
|
|
|
|
UNLOCK(&g_EventLogCritSec);
|
|
}
|
|
|
|
if( g_hEventLog )
|
|
{
|
|
WCHAR *wszStringEmpty = L"";
|
|
|
|
if (NULL == apwszStrings)
|
|
apwszStrings = &wszStringEmpty;
|
|
|
|
if ( !ReportEvent( g_hEventLog,
|
|
wEventType,
|
|
0,
|
|
dwEventId,
|
|
NULL,
|
|
cStrings,
|
|
0,
|
|
apwszStrings,
|
|
NULL ) )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LogEvent: could not log event: 0x%x\n", GetLastError() );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
Ascii2Wchar
|
|
|
|
Description:
|
|
|
|
Convert an ascii string to a wide character string. This function is only
|
|
defined if UNICODE is defined. This function allocates memory for the
|
|
return value of the wide character string.
|
|
|
|
Arguments:
|
|
|
|
lpszAsciiStr - Points to the ascii string
|
|
ppwszWideStr - Points to the pointer to the wide character string.
|
|
|
|
Return:
|
|
|
|
LICENSE_STATUS_OK if successful or a LICENSE_STATUS error code otherwise.
|
|
|
|
--*/
|
|
|
|
LICENSE_STATUS
|
|
Ascii2Wchar
|
|
(
|
|
LPSTR lpszAsciiStr,
|
|
LPWSTR * ppwszWideStr )
|
|
{
|
|
LICENSE_STATUS
|
|
Status;
|
|
|
|
if( ( NULL == lpszAsciiStr ) || ( NULL == ppwszWideStr ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
//
|
|
// allocate memory for the wide string
|
|
//
|
|
|
|
|
|
//
|
|
// Allocate extra space for NULL, mbstowcs() does not NULL terminate string
|
|
//
|
|
|
|
Status = LicenseMemoryAllocate(
|
|
( _mbslen( lpszAsciiStr ) + 2 ) * sizeof( WCHAR ),
|
|
ppwszWideStr );
|
|
|
|
if( LICENSE_STATUS_OK != Status )
|
|
{
|
|
return( Status );
|
|
}
|
|
|
|
if( 0 >= mbstowcs( *ppwszWideStr, lpszAsciiStr, _mbslen( lpszAsciiStr ) + 1 ) )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "LICPROT: Ascii2Wchar: cannot convert ascii string to wide char\n" );
|
|
#endif
|
|
Status = LICENSE_STATUS_INVALID_INPUT;
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
#endif
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
QueryLicenseInfo
|
|
|
|
Description:
|
|
|
|
Query the license information provided by the client
|
|
|
|
Parameters:
|
|
|
|
pLicenseContext - License protocol context
|
|
pTsLicenseInfo - Pointer to license information
|
|
|
|
Return:
|
|
|
|
If successful, pTsLicenseInfo will contain the license info and this
|
|
function returns LICENSE_STATUS_SUCCESS. Otherwise, returns a
|
|
LICENSE_STATUS error.
|
|
|
|
--*/
|
|
|
|
LICENSE_STATUS
|
|
QueryLicenseInfo(
|
|
HANDLE hContext,
|
|
PTS_LICENSE_INFO pTsLicenseInfo )
|
|
{
|
|
PHS_Protocol_Context
|
|
pLicenseContext = (PHS_Protocol_Context) hContext;
|
|
LICENSE_STATUS
|
|
Status;
|
|
|
|
if( ( NULL == hContext ) || ( NULL == pTsLicenseInfo ) )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
if( NULL == pLicenseContext->pTsLicenseInfo )
|
|
{
|
|
return( LICENSE_STATUS_NO_LICENSE_ERROR );
|
|
}
|
|
|
|
//
|
|
// indicate if the license is temporary
|
|
//
|
|
|
|
pTsLicenseInfo->fTempLicense = pLicenseContext->pTsLicenseInfo->fTempLicense;
|
|
|
|
//
|
|
// license validity dates
|
|
//
|
|
|
|
pTsLicenseInfo->NotAfter = pLicenseContext->pTsLicenseInfo->NotAfter;
|
|
|
|
//
|
|
// raw license data
|
|
//
|
|
|
|
if (NULL != pTsLicenseInfo->pbRawLicense)
|
|
{
|
|
LicenseMemoryFree( &pTsLicenseInfo->pbRawLicense );
|
|
}
|
|
|
|
|
|
Status = LicenseMemoryAllocate(
|
|
pLicenseContext->pTsLicenseInfo->cbRawLicense,
|
|
&(pTsLicenseInfo->pbRawLicense));
|
|
|
|
if (Status != LICENSE_STATUS_OK)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
memcpy(pTsLicenseInfo->pbRawLicense,
|
|
pLicenseContext->pTsLicenseInfo->pbRawLicense,
|
|
pLicenseContext->pTsLicenseInfo->cbRawLicense);
|
|
|
|
pTsLicenseInfo->cbRawLicense
|
|
= pLicenseContext->pTsLicenseInfo->cbRawLicense;
|
|
|
|
//
|
|
// flags
|
|
//
|
|
|
|
pTsLicenseInfo->dwSupportFlags
|
|
= pLicenseContext->pTsLicenseInfo->dwSupportFlags;
|
|
|
|
return( LICENSE_STATUS_OK );
|
|
}
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
FreeLicenseInfo
|
|
|
|
Description:
|
|
|
|
Free the memory allocated for the elements in the TS_LICENSE_INFO structure.
|
|
|
|
Parameters:
|
|
|
|
pTsLicenseInfo - Pointer to a TS_LICENSE_INFO structure
|
|
|
|
Returns:
|
|
|
|
Nothing.
|
|
|
|
--*/
|
|
|
|
VOID
|
|
FreeLicenseInfo(
|
|
PTS_LICENSE_INFO pTsLicenseInfo )
|
|
{
|
|
FreeTsLicenseInfo( pTsLicenseInfo );
|
|
return;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
LICENSE_STATUS
|
|
AcceptProtocolContext(
|
|
IN HANDLE hContext,
|
|
IN DWORD cbInBuf,
|
|
IN PBYTE pInBuf,
|
|
IN OUT DWORD * pcbOutBuf,
|
|
IN OUT PBYTE * ppOutBuf )
|
|
{
|
|
PHS_Protocol_Context pLicenseContext;
|
|
LICENSE_STATUS Status;
|
|
|
|
pLicenseContext = ( PHS_Protocol_Context )hContext;
|
|
|
|
LOCK( &pLicenseContext->CritSec );
|
|
|
|
if( INIT == pLicenseContext->State )
|
|
{
|
|
//
|
|
// Generate a hydra server hello message to request for client
|
|
// license
|
|
//
|
|
|
|
Status = CreateHydraServerHello(pLicenseContext,
|
|
cbInBuf,
|
|
pInBuf,
|
|
pcbOutBuf,
|
|
ppOutBuf);
|
|
goto done;
|
|
|
|
}
|
|
else if( SENT_SERVER_HELLO == pLicenseContext->State )
|
|
{
|
|
//
|
|
// Hello response from the client
|
|
//
|
|
|
|
Status = HandleHelloResponse(pLicenseContext,
|
|
cbInBuf,
|
|
pInBuf,
|
|
pcbOutBuf,
|
|
ppOutBuf);
|
|
goto done;
|
|
}
|
|
else if( ISSUED_PLATFORM_CHALLENGE == pLicenseContext->State )
|
|
{
|
|
//
|
|
// Handle the platform challenge response
|
|
//
|
|
|
|
Status = HandlePlatformChallengeResponse(pLicenseContext,
|
|
cbInBuf,
|
|
pInBuf,
|
|
pcbOutBuf,
|
|
ppOutBuf);
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
Status = LICENSE_STATUS_INVALID_SERVER_CONTEXT;
|
|
}
|
|
|
|
//
|
|
// check other states to create other messages as required...
|
|
//
|
|
|
|
done:
|
|
|
|
//
|
|
// handle any error before returning.
|
|
//
|
|
// If the current status is LICENSE_STATUS_SERVER_ABORT, it means
|
|
// that we have already tried to handle the error conditions
|
|
// with no success and the only option is to abort without
|
|
// informing the client licensing protocol.
|
|
//
|
|
|
|
if( ( LICENSE_STATUS_OK != Status ) &&
|
|
( LICENSE_STATUS_CONTINUE != Status ) &&
|
|
( LICENSE_STATUS_ISSUED_LICENSE != Status ) &&
|
|
( LICENSE_STATUS_SEND_ERROR != Status ) &&
|
|
( LICENSE_STATUS_SERVER_ABORT != Status ) &&
|
|
( LICENSE_STATUS_INVALID_SERVER_CONTEXT != Status ) )
|
|
{
|
|
HandleErrorCondition( pLicenseContext, pcbOutBuf, ppOutBuf, &Status );
|
|
}
|
|
|
|
UNLOCK( &pLicenseContext->CritSec );
|
|
|
|
return( Status );
|
|
}
|
|
|
|
LICENSE_STATUS
|
|
RequestNewLicense(
|
|
IN HANDLE hContext,
|
|
IN TCHAR *tszLicenseServerName,
|
|
IN LICENSEREQUEST *pLicenseRequest,
|
|
IN TCHAR *tszComputerName,
|
|
IN TCHAR *tszUserName,
|
|
IN BOOL fAcceptTempLicense,
|
|
IN BOOL fAcceptFewerLicenses,
|
|
IN DWORD *pdwQuantity,
|
|
OUT DWORD *pcbLicense,
|
|
OUT PBYTE *ppbLicense
|
|
)
|
|
{
|
|
PHS_Protocol_Context pLicenseContext;
|
|
LICENSE_STATUS LsStatus;
|
|
DWORD dwChallengeResponse = 0;
|
|
DWORD RpcStatus;
|
|
DWORD dwSupportFlags = SUPPORT_PER_SEAT_REISSUANCE;
|
|
BOOL fRetried = FALSE;
|
|
|
|
pLicenseContext = ( PHS_Protocol_Context )hContext;
|
|
|
|
LOCK( &pLicenseContext->CritSec );
|
|
|
|
reconnect:
|
|
if (NULL != tszLicenseServerName)
|
|
{
|
|
LsStatus = CheckConnectNamedLicenseServer(pLicenseContext,
|
|
tszLicenseServerName);
|
|
}
|
|
else
|
|
{
|
|
LsStatus = CheckConnectLicenseServer(pLicenseContext);
|
|
}
|
|
|
|
if( LICENSE_STATUS_OK != LsStatus )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
RpcStatus = TLSIssueNewLicenseExEx(
|
|
pLicenseContext->hLSHandle,
|
|
&dwSupportFlags,
|
|
0, // Challenge Context
|
|
pLicenseRequest,
|
|
tszComputerName,
|
|
tszUserName,
|
|
sizeof(DWORD), // cbChallengeResponse
|
|
(PBYTE) &dwChallengeResponse,
|
|
fAcceptTempLicense,
|
|
fAcceptFewerLicenses,
|
|
pdwQuantity,
|
|
pcbLicense,
|
|
ppbLicense,
|
|
&LsStatus );
|
|
|
|
if ( RPC_S_OK != RpcStatus )
|
|
{
|
|
if (!fRetried)
|
|
{
|
|
fRetried = TRUE;
|
|
pLicenseContext->hLSHandle = NULL;
|
|
goto reconnect;
|
|
}
|
|
else
|
|
{
|
|
LsStatus = LICENSE_STATUS_NO_LICENSE_SERVER;
|
|
}
|
|
}
|
|
else if ( LSERVER_ERROR_BASE <= LsStatus )
|
|
{
|
|
LsStatus = LsStatusToLicenseStatus(LsStatus,
|
|
LICENSE_STATUS_NO_LICENSE_ERROR);
|
|
}
|
|
|
|
done:
|
|
|
|
UNLOCK( &pLicenseContext->CritSec );
|
|
|
|
return LsStatus;
|
|
}
|
|
|
|
// TODO: Generalize this for all license types
|
|
|
|
LICENSE_STATUS
|
|
ReturnInternetLicense(
|
|
IN HANDLE hContext,
|
|
IN TCHAR *tszLicenseServer,
|
|
IN LICENSEREQUEST *pLicenseRequest,
|
|
IN ULARGE_INTEGER ulSerialNumber,
|
|
IN DWORD dwQuantity
|
|
)
|
|
{
|
|
PHS_Protocol_Context pLicenseContext;
|
|
LICENSE_STATUS LsStatus;
|
|
DWORD RpcStatus;
|
|
BOOL fRetried = FALSE;
|
|
|
|
pLicenseContext = ( PHS_Protocol_Context )hContext;
|
|
|
|
LOCK( &pLicenseContext->CritSec );
|
|
|
|
|
|
reconnect:
|
|
if (NULL != tszLicenseServer)
|
|
{
|
|
LsStatus = CheckConnectNamedLicenseServer(pLicenseContext,
|
|
tszLicenseServer);
|
|
}
|
|
else
|
|
{
|
|
LsStatus = CheckConnectLicenseServer(pLicenseContext);
|
|
}
|
|
|
|
if (LICENSE_STATUS_OK != LsStatus)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
RpcStatus = TLSReturnInternetLicenseEx(
|
|
pLicenseContext->hLSHandle,
|
|
pLicenseRequest,
|
|
&ulSerialNumber,
|
|
dwQuantity,
|
|
&LsStatus );
|
|
|
|
if ( RPC_S_OK != RpcStatus )
|
|
{
|
|
if (!fRetried)
|
|
{
|
|
fRetried = TRUE;
|
|
pLicenseContext->hLSHandle = NULL;
|
|
goto reconnect;
|
|
}
|
|
else
|
|
{
|
|
LsStatus = LICENSE_STATUS_NO_LICENSE_SERVER;
|
|
}
|
|
}
|
|
else if ( LSERVER_ERROR_BASE <= LsStatus )
|
|
{
|
|
LsStatus = LsStatusToLicenseStatus(LsStatus,
|
|
LICENSE_STATUS_NOT_SUPPORTED);
|
|
}
|
|
|
|
done:
|
|
|
|
UNLOCK( &pLicenseContext->CritSec );
|
|
|
|
return( LsStatus );
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FileTimeToUnixTime
|
|
*
|
|
* Convert FILETIME to UNIX time (time_t)
|
|
*
|
|
* ENTRY:
|
|
* pft (input)
|
|
* pointer FILETIME structure
|
|
* t (input/output)
|
|
* pointer to UNIX time
|
|
*
|
|
* EXIT:
|
|
* TRUE - Success
|
|
* FALSE - Failure
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL
|
|
FileTimeToUnixTime(
|
|
LPFILETIME pft,
|
|
time_t * t
|
|
)
|
|
{
|
|
SYSTEMTIME sysTime;
|
|
struct tm gmTime;
|
|
|
|
if( FileTimeToSystemTime( pft, &sysTime ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( sysTime.wYear >= 2038 )
|
|
{
|
|
*t = INT_MAX;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Unix time support up to 2038/1/18
|
|
// restrict any expiration data
|
|
//
|
|
|
|
memset( &gmTime, 0, sizeof( gmTime ) );
|
|
gmTime.tm_sec = sysTime.wSecond;
|
|
gmTime.tm_min = sysTime.wMinute;
|
|
gmTime.tm_hour = sysTime.wHour;
|
|
gmTime.tm_year = sysTime.wYear - 1900;
|
|
gmTime.tm_mon = sysTime.wMonth - 1;
|
|
gmTime.tm_mday = sysTime.wDay;
|
|
|
|
*t = mktime( &gmTime );
|
|
}
|
|
|
|
return( *t != ( time_t )-1 );
|
|
}
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
DaysToExpiration
|
|
|
|
Description:
|
|
|
|
Return expiration info from the client license
|
|
|
|
Parameters:
|
|
|
|
hContext - License protocol context
|
|
pdwDaysLeft - Number of days to expiration is returned here. If the
|
|
license has already expired, this is 0. If the
|
|
license has no expiration date, this is 0xFFFFFFFF
|
|
pfTemporary - Whether the license is temporary is returned here
|
|
|
|
Return:
|
|
|
|
If successful, the output parameters are filled in, and this
|
|
function returns LICENSE_STATUS_SUCCESS. Otherwise, returns a
|
|
LICENSE_STATUS error.
|
|
|
|
--*/
|
|
|
|
LICENSE_STATUS
|
|
DaysToExpiration(
|
|
HANDLE hContext,
|
|
DWORD *pdwDaysLeft,
|
|
BOOL *pfTemporary
|
|
)
|
|
{
|
|
PHS_Protocol_Context
|
|
pLicenseContext = (PHS_Protocol_Context) hContext;
|
|
time_t
|
|
Expiration,
|
|
CurrentTime;
|
|
|
|
if ( NULL == hContext )
|
|
{
|
|
return( LICENSE_STATUS_INVALID_INPUT );
|
|
}
|
|
|
|
if( NULL == pLicenseContext->pTsLicenseInfo )
|
|
{
|
|
return( LICENSE_STATUS_NO_LICENSE_ERROR );
|
|
}
|
|
|
|
//
|
|
// indicate if the license is temporary
|
|
//
|
|
|
|
if (NULL != pfTemporary)
|
|
{
|
|
*pfTemporary = pLicenseContext->pTsLicenseInfo->fTempLicense;
|
|
}
|
|
|
|
//
|
|
// license validity dates
|
|
//
|
|
|
|
if (NULL != pdwDaysLeft)
|
|
{
|
|
if ( FALSE == FileTimeToUnixTime( &pLicenseContext->pTsLicenseInfo->NotAfter, &Expiration ) )
|
|
{
|
|
return (LICENSE_STATUS_INVALID_CLIENT_CONTEXT);
|
|
}
|
|
|
|
if (PERMANENT_LICENSE_EXPIRE_DATE == Expiration)
|
|
{
|
|
*pdwDaysLeft = 0xFFFFFFFF;
|
|
}
|
|
else
|
|
{
|
|
time( &CurrentTime );
|
|
|
|
if( CurrentTime >= Expiration )
|
|
{
|
|
//
|
|
// license already expired
|
|
//
|
|
|
|
*pdwDaysLeft = 0;
|
|
}
|
|
|
|
//
|
|
// figure out how many more days to go before license expires
|
|
//
|
|
|
|
*pdwDaysLeft = (DWORD)(( Expiration - CurrentTime ) / SECONDS_IN_A_DAY);
|
|
}
|
|
}
|
|
|
|
return( LICENSE_STATUS_OK );
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
MarkLicenseFlags
|
|
|
|
Description:
|
|
|
|
Marks the license at the license server as being used in a valid logon.
|
|
|
|
--*/
|
|
|
|
LICENSE_STATUS
|
|
MarkLicenseFlags(
|
|
HANDLE hContext,
|
|
UCHAR ucFlags
|
|
)
|
|
{
|
|
PHS_Protocol_Context pLicenseContext;
|
|
LICENSE_STATUS LsStatus;
|
|
DWORD RpcStatus;
|
|
BOOL fRetried = FALSE;
|
|
|
|
pLicenseContext = ( PHS_Protocol_Context )hContext;
|
|
|
|
if( NULL == pLicenseContext->pTsLicenseInfo )
|
|
{
|
|
return( LICENSE_STATUS_NO_LICENSE_ERROR );
|
|
}
|
|
|
|
if (!pLicenseContext->pTsLicenseInfo->fTempLicense)
|
|
{
|
|
return LICENSE_STATUS_OK;
|
|
}
|
|
|
|
LOCK( &pLicenseContext->CritSec );
|
|
|
|
reconnect:
|
|
LsStatus = CheckConnectLicenseServer(pLicenseContext);
|
|
|
|
if( LICENSE_STATUS_OK != LsStatus )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
RpcStatus = TLSMarkLicense(
|
|
pLicenseContext->hLSHandle,
|
|
ucFlags,
|
|
pLicenseContext->pTsLicenseInfo->cbRawLicense,
|
|
pLicenseContext->pTsLicenseInfo->pbRawLicense,
|
|
&LsStatus );
|
|
|
|
if ( RPC_S_OK != RpcStatus )
|
|
{
|
|
if (!fRetried)
|
|
{
|
|
fRetried = TRUE;
|
|
pLicenseContext->hLSHandle = NULL;
|
|
goto reconnect;
|
|
}
|
|
else
|
|
{
|
|
LsStatus = LICENSE_STATUS_NO_LICENSE_SERVER;
|
|
}
|
|
}
|
|
else if ( LSERVER_ERROR_BASE <= LsStatus )
|
|
{
|
|
LsStatus = LsStatusToLicenseStatus(LsStatus,
|
|
LICENSE_STATUS_NOT_SUPPORTED);
|
|
}
|
|
|
|
done:
|
|
UNLOCK( &pLicenseContext->CritSec );
|
|
|
|
return LsStatus;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
CacheRawLicenseData
|
|
|
|
Description:
|
|
|
|
Caches the unpacked license bits in the TS_LICENSE_INFO for later use.
|
|
The TS_LICENSE_INFO struct should already be created.
|
|
|
|
--*/
|
|
|
|
LICENSE_STATUS
|
|
CacheRawLicenseData(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
PBYTE pbRawLicense,
|
|
DWORD cbRawLicense
|
|
)
|
|
{
|
|
LICENSE_STATUS Status;
|
|
|
|
if ((pLicenseContext == NULL) || (pLicenseContext->pTsLicenseInfo == NULL))
|
|
{
|
|
return(LICENSE_STATUS_INVALID_INPUT);
|
|
}
|
|
|
|
if (pLicenseContext->pTsLicenseInfo->pbRawLicense != NULL)
|
|
{
|
|
LicenseMemoryFree(&(pLicenseContext->pTsLicenseInfo->pbRawLicense));
|
|
}
|
|
|
|
Status = LicenseMemoryAllocate(cbRawLicense,
|
|
&(pLicenseContext->pTsLicenseInfo->pbRawLicense));
|
|
|
|
if (Status == LICENSE_STATUS_OK)
|
|
{
|
|
memcpy(pLicenseContext->pTsLicenseInfo->pbRawLicense, pbRawLicense,
|
|
cbRawLicense);
|
|
|
|
pLicenseContext->pTsLicenseInfo->cbRawLicense = cbRawLicense;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
SetExtendedData
|
|
|
|
Description:
|
|
|
|
Sets the new fields in the TsLicenseInfo.
|
|
|
|
--*/
|
|
|
|
LICENSE_STATUS
|
|
SetExtendedData(
|
|
PHS_Protocol_Context pLicenseContext,
|
|
DWORD dwSupportFlags
|
|
)
|
|
{
|
|
if ((pLicenseContext == NULL) || (pLicenseContext->pTsLicenseInfo == NULL))
|
|
{
|
|
return(LICENSE_STATUS_INVALID_INPUT);
|
|
}
|
|
|
|
pLicenseContext->pTsLicenseInfo->dwSupportFlags = dwSupportFlags;
|
|
|
|
return(LICENSE_STATUS_OK);
|
|
}
|
|
|
|
/*++
|
|
|
|
Function:
|
|
|
|
LsStatusToLicenseStatus
|
|
|
|
Description:
|
|
|
|
Map a license server error code to a LICENSE_STATUS
|
|
|
|
--*/
|
|
|
|
LICENSE_STATUS
|
|
LsStatusToLicenseStatus(
|
|
DWORD LsStatus,
|
|
DWORD LsStatusDefault
|
|
)
|
|
{
|
|
LICENSE_STATUS LicenseStatus;
|
|
|
|
switch (LsStatus)
|
|
{
|
|
case LSERVER_S_SUCCESS:
|
|
LicenseStatus = LICENSE_STATUS_OK;
|
|
break;
|
|
|
|
case LSERVER_E_OUTOFMEMORY:
|
|
LicenseStatus = LICENSE_STATUS_OUT_OF_MEMORY;
|
|
break;
|
|
|
|
case LSERVER_E_INVALID_DATA:
|
|
LicenseStatus = LICENSE_STATUS_INVALID_INPUT;
|
|
break;
|
|
|
|
case LSERVER_E_LS_NOTPRESENT:
|
|
case LSERVER_E_LS_NOTRUNNING:
|
|
LicenseStatus = LICENSE_STATUS_NO_LICENSE_SERVER;
|
|
break;
|
|
|
|
case LSERVER_E_NO_LICENSE:
|
|
case LSERVER_E_NO_PRODUCT:
|
|
case LSERVER_E_NO_CERTIFICATE: // not activated
|
|
LicenseStatus = LICENSE_STATUS_NO_LICENSE_ERROR;
|
|
break;
|
|
|
|
case LSERVER_E_INTERNAL_ERROR:
|
|
LicenseStatus = LICENSE_STATUS_UNSPECIFIED_ERROR;
|
|
break;
|
|
|
|
default:
|
|
LicenseStatus = LsStatusDefault;
|
|
break;
|
|
}
|
|
|
|
return LicenseStatus;
|
|
}
|