windows-nt/Source/XPSP1/NT/termsrv/license/tlserver/server/db.cpp
2020-09-26 16:20:57 +08:00

884 lines
25 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996-1998
//
// File: db.cpp
//
// Contents:
// all routine deal with cross table query
//
// History:
// Feb 4, 98 HueiWang Created
//---------------------------------------------------------------------------
#include "pch.cpp"
#include "globals.h"
#include "db.h"
#include "clilic.h"
#include "keypack.h"
#include "kp.h"
#include "lkpdesc.h"
/****************************************************************************
Function:
LSDBValidateLicense()
Description:
Routine to validate license agaist database, must call LSDecodeLicense()
to convert hydra license to LICENSEREQUEST structure.
Arguments:
IN CSQLStmt* - SQL Statement handle to use
IN PLICENSEREQUEST - License in the form of LICENSEREQUEST structure
IN dwKeyPackId - KeyPack table's ID that is license is issued from
IN dwLicenseId - License tables's License ID
OUT LPKEYPACK - KeyPack record this license is issued from, NULL if not
interested in this value.
OUT LPLICENSE - Corresponding license record for this license, NULL if
not interest in this value.
Returns:
ERROR_SUCCESS
TLS_E_INVALID_LICENSE
TLS_E_INTERNAL
ODBC error.
****************************************************************************/
DWORD
TLSDBValidateLicense(
PTLSDbWorkSpace pDbWkSpace,
//IN PBYTE pbLicense,
//IN DWORD cbLicense,
IN PHWID phWid,
IN PLICENSEREQUEST pLicensedProduct,
IN DWORD dwKeyPackId,
IN DWORD dwLicenseId,
OUT PTLSLICENSEPACK lpKeyPack,
OUT LPLICENSEDCLIENT lpLicense
)
/*
*/
{
DWORD dwStatus=ERROR_SUCCESS;
DWORD dwMatchCount=0;
if(pDbWkSpace == NULL)
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
TLSASSERT(FALSE);
return dwStatus;
}
TLSLICENSEPACK keypack_search;
TLSLICENSEPACK keypack_found;
LICENSEDCLIENT license_search;
LICENSEDCLIENT license_found;
int count=0;
BOOL bValid=TRUE;
memset(&license_search, 0, sizeof(LICENSEDCLIENT));
keypack_found.pbDomainSid = NULL;
license_search.dwLicenseId = dwLicenseId;
dwStatus = TLSDBLicenseEnumBegin(
pDbWkSpace,
TRUE,
LSLICENSE_SEARCH_LICENSEID,
&license_search
);
if(dwStatus != ERROR_SUCCESS)
{
if(IS_JB_ERROR(dwStatus) != TRUE)
{
SetLastError(dwStatus = TLS_E_INVALID_LICENSE);
}
goto cleanup;
}
do
{
dwStatus=TLSDBLicenseEnumNext(
pDbWkSpace,
&license_found
);
if(dwStatus != ERROR_SUCCESS)
break;
count++;
} while(count < 1);
TLSDBLicenseEnumEnd(pDbWkSpace);
if(count != 1)
{
// can't find the license
SetLastError(dwStatus = TLS_E_INVALID_LICENSE);
goto cleanup;
}
if(count > 1)
{
// more than one entry in database has identical
// license id
SetLastError(dwStatus = TLS_E_INTERNAL);
goto cleanup;
}
//
// Not issue by this license server???
//
if(license_found.dwKeyPackId != dwKeyPackId)
{
SetLastError(dwStatus = TLS_E_INVALID_LICENSE);
goto cleanup;
}
//
// new license request might pass different HWID
//
dwMatchCount += (int)(license_found.dwSystemBiosChkSum == phWid->dwPlatformID);
dwMatchCount += (int)(license_found.dwVideoBiosChkSum == phWid->Data1);
dwMatchCount += (int)(license_found.dwFloppyBiosChkSum == phWid->Data2);
dwMatchCount += (int)(license_found.dwHardDiskSize == phWid->Data3);
dwMatchCount += (int)(license_found.dwRamSize == phWid->Data4);
if(dwMatchCount < LICENSE_MIN_MATCH)
{
SetLastError(dwStatus = TLS_E_INVALID_LICENSE);
}
//
// Verify against KeyPack Table
//
memset(&keypack_search, 0, sizeof(keypack_search));
keypack_search.dwKeyPackId = dwKeyPackId;
dwStatus = TLSDBKeyPackFind(
pDbWkSpace,
TRUE,
LSKEYPACK_EXSEARCH_DWINTERNAL,
&keypack_search,
&keypack_found
);
if(dwStatus != ERROR_SUCCESS)
{
if(IS_JB_ERROR(dwStatus) != TRUE)
{
SetLastError(dwStatus = TLS_E_INVALID_LICENSE);
}
goto cleanup;
}
// match KeyPack's Product ID, Version, Language ID, PlatformID
// structure change, no more product version.
if(pLicensedProduct->dwPlatformID != keypack_found.dwPlatformType ||
_tcsicmp((LPTSTR)pLicensedProduct->pProductInfo->pbCompanyName, keypack_found.szCompanyName) ||
_tcsicmp((LPTSTR)pLicensedProduct->pProductInfo->pbProductID, keypack_found.szProductId) )
{
SetLastError(dwStatus = TLS_E_INVALID_LICENSE);
}
cleanup:
//FreeTlsLicensePack(&keypack_found);
if(dwStatus == ERROR_SUCCESS)
{
if(lpKeyPack)
{
*lpKeyPack = keypack_found;
}
if(lpLicense)
{
*lpLicense = license_found;
}
}
return dwStatus;
}
/*************************************************************************
Function:
LSDBDeleteLicense()
*************************************************************************/
DWORD
TLSDBDeleteLicense(
PTLSDbWorkSpace pDbWkSpace,
IN DWORD dwKeyPackId,
DWORD dwLicenseId
)
/*
*/
{
// TODO - license entry base on license id
// 1) Return license back to key pack
// 2) 'Physically' delete the license.
return ERROR_SUCCESS;
}
/*************************************************************************
Function:
LSDBRevokeLicense()
*************************************************************************/
DWORD
TLSDBRevokeLicense(
PTLSDbWorkSpace pDbWkSpace,
IN DWORD dwKeyPacKId,
IN DWORD dwLicenseId
)
{
// Set License Status to revoked
// Return License to KeyPack
// call LSDBDeleteKeyPack() and if not successful, insert into RevokeLicenseTable
return ERROR_SUCCESS;
}
/*************************************************************************
Function:
LSDBReturnLicense()
*************************************************************************/
DWORD
TLSDBReturnLicense(
PTLSDbWorkSpace pDbWkSpace,
IN DWORD dwKeyPackId,
IN DWORD dwLicenseId,
IN DWORD dwNewLicenseStatus
)
/*
*/
{
DWORD dwStatus=ERROR_SUCCESS;
DWORD dwQuantity = 1;
TLSDBLockKeyPackTable();
TLSDBLockLicenseTable();
//
// no verification on record got updated.
//
LICENSEDCLIENT license;
license.dwLicenseId = dwLicenseId;
license.ucLicenseStatus = dwNewLicenseStatus;
//
// use undocumented feature to delete license
//
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_RETURN,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("Deleting license ID %d issued by keypack %d\n"),
license.dwLicenseId,
dwKeyPackId
);
if (dwNewLicenseStatus == LSLICENSESTATUS_DELETE)
{
// get number of CALs in this license
LICENSEDCLIENT licenseFound;
dwStatus = TLSDBLicenseFind(
pDbWkSpace,
TRUE,
LSLICENSE_SEARCH_LICENSEID,
&license,
&licenseFound
);
if(dwStatus == ERROR_SUCCESS)
{
dwQuantity = licenseFound.dwNumLicenses;
}
}
dwStatus = TLSDBLicenseSetValue(
pDbWkSpace,
LSLICENSE_EXSEARCH_LICENSESTATUS,
&license,
FALSE
);
if(dwStatus == ERROR_SUCCESS && dwNewLicenseStatus == LSLICENSESTATUS_DELETE)
{
dwStatus = TLSDBReturnLicenseToKeyPack(
pDbWkSpace,
dwKeyPackId,
dwQuantity
);
}
TLSDBUnlockLicenseTable();
TLSDBUnlockKeyPackTable();
return dwStatus;
}
/*************************************************************************
Function:
LSDBReturnLicenseToKeyPack()
*************************************************************************/
DWORD
TLSDBReturnLicenseToKeyPack(
IN PTLSDbWorkSpace pDbWkSpace,
IN DWORD dwKeyPackId,
IN int dwNumLicense
)
{
DWORD dwStatus = ERROR_SUCCESS;
TLSDBLockKeyPackTable();
#ifdef DBG
DWORD dwPrevNumLicense=0;
#endif
TLSLICENSEPACK found;
TLSLICENSEPACK search;
found.pbDomainSid = NULL;
do {
// retrieve number of licenses
search.dwKeyPackId = dwKeyPackId;
dwStatus = TLSDBKeyPackFind(
pDbWkSpace,
TRUE,
LSKEYPACK_EXSEARCH_DWINTERNAL,
&search,
&found
);
if(dwStatus != ERROR_SUCCESS)
{
if(IS_JB_ERROR(dwStatus) == FALSE)
{
SetLastError(dwStatus = TLS_E_RECORD_NOTFOUND);
}
break;
}
if(search.dwKeyPackId != found.dwKeyPackId)
{
TLSASSERT(FALSE);
}
#ifdef DBG
dwPrevNumLicense = found.dwNumberOfLicenses;
#endif
// set the number of licenses issued by 1
switch( (found.ucAgreementType & ~LSKEYPACK_RESERVED_TYPE) )
{
case LSKEYPACKTYPE_RETAIL:
case LSKEYPACKTYPE_CONCURRENT:
case LSKEYPACKTYPE_OPEN:
case LSKEYPACKTYPE_SELECT:
// number of licenses available
found.dwNumberOfLicenses += dwNumLicense;
break;
case LSKEYPACKTYPE_FREE:
case LSKEYPACKTYPE_TEMPORARY:
// number of license issued
if(found.dwNumberOfLicenses > 0)
{
found.dwNumberOfLicenses -= dwNumLicense;
}
break;
default:
SetLastError(dwStatus = TLS_E_CORRUPT_DATABASE);
}
#ifdef DBG
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_RETURN,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("Returning license to keypack %d - from %d to %d\n"),
found.dwKeyPackId,
dwPrevNumLicense,
found.dwNumberOfLicenses
);
#endif
//
// use undocumented feature to delete temp. keypack
if( (found.ucAgreementType & ~LSKEYPACK_RESERVED_TYPE) == LSKEYPACKTYPE_TEMPORARY &&
found.dwNumberOfLicenses == 0)
{
found.ucKeyPackStatus = LSKEYPACKSTATUS_DELETE;
// delete keypack desc table
LICPACKDESC keyPackDesc;
memset(&keyPackDesc, 0, sizeof(LICPACKDESC));
keyPackDesc.dwKeyPackId = found.dwKeyPackId;
TLSDBKeyPackDescSetValue(
pDbWkSpace,
KEYPACKDESC_SET_DELETE_ENTRY,
&keyPackDesc
);
}
dwStatus=TLSDBKeyPackSetValues(
pDbWkSpace,
TRUE,
LSKEYPACK_EXSEARCH_AVAILABLE,
&found
);
} while(FALSE);
//FreeTlsLicensePack(&found);
TLSDBUnlockKeyPackTable();
return dwStatus;
}
/*************************************************************************
Function:
LSDBRevokeKeyPack()
*************************************************************************/
DWORD
TLSDBRevokeKeyPack(
IN PTLSDbWorkSpace pDbWkSpace,
IN DWORD dwKeyPackId
)
{
// Set Key Pack Status to Revoke
// Insert this key pack into RevokeKeyPackTable ???
return ERROR_SUCCESS;
}
/*************************************************************************
Function:
LSDBReturnKeyPack()
*************************************************************************/
DWORD
TLSDBReturnKeyPack(
IN PTLSDbWorkSpace pDbWkSpace,
IN DWORD dwKeyPackId
)
{
// Same as RevokeKeyPack except status is return
// Delete Key pack only when all license has been returned.
return ERROR_SUCCESS;
}
/*************************************************************************
Function:
LSDBDeleteKeyPack()
*************************************************************************/
DWORD
TLSDBDeleteKeyPack(
PTLSDbWorkSpace pDbWkSpace,
IN DWORD dwKeyPackId
)
{
// Delete Only when all license has been returned.
return ERROR_SUCCESS;
}
//+------------------------------------------------------------------------
// Function:
// AllocateLicenses()
//
// Description:
// Allocate license from key Pack
//
// Arguments:
// IN lpSqlStmt - sql statement handle
// IN ucKeyPackType - key pack type to allocate license from
// IN szCompanyName - Product Company
// IN szProductId - Product Name
// IN dwVersion - Product Version
// IN dwPlatformId - Product PlatformId
// IN dwLangId - Product Lanugage Id
// IN OUT lpdwNumLicense - number of license to be allocated and on
// return, number of licenses actually allocated
// IN bufSize - number of interested keypack that has requested license
// IN OUT lpAllocationVector - number of license allocated from list of
// key pack that has requested licenses.
// IN OUT LPKEYPACK - key Pack that license was allocated from
//
// Returns:
// TLS_E_INVALID_DATA Invalid parameter
// TLS_I_NO_MORE_DATA No key pack has the requested license
//
// Notes:
// To keep code clean/simple, call ReturnLicenses() for returning
// licenses
//-------------------------------------------------------------------------
DWORD
VerifyTLSDBAllocateRequest(
IN PTLSDBAllocateRequest pRequest
)
/*
*/
{
DWORD dwStatus = ERROR_SUCCESS;
UCHAR ucAgreementType;
if(pRequest == NULL)
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
goto cleanup;
}
ucAgreementType = (pRequest->ucAgreementType & ~pRequest->ucAgreementType);
if(ucAgreementType < LSKEYPACKTYPE_FIRST || ucAgreementType > LSKEYPACKTYPE_LAST)
{
DBGPrintf(
DBG_ERROR,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
DBG_ALL_LEVEL,
_TEXT("AllocateLicenses() invalid keypack type - %d\n"),
pRequest->ucAgreementType
);
SetLastError(dwStatus = TLS_E_INVALID_DATA);
goto cleanup;
}
if(pRequest->szCompanyName == NULL || _tcslen(pRequest->szCompanyName) == 0)
{
DBGPrintf(
DBG_ERROR,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
DBG_ALL_LEVEL,
_TEXT("AllocateLicenses() invalid company name\n")
);
SetLastError(dwStatus = TLS_E_INVALID_DATA);
goto cleanup;
}
if(pRequest->szProductId == NULL || _tcslen(pRequest->szProductId) == 0)
{
DBGPrintf(
DBG_ERROR,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
DBG_ALL_LEVEL,
_TEXT("AllocateLicenses() invalid product id\n")
);
SetLastError(dwStatus = TLS_E_INVALID_DATA);
}
cleanup:
return dwStatus;
}
//----------------------------------------------------------------------
DWORD
AllocateLicensesFromDB(
IN PTLSDbWorkSpace pDbWkSpace,
IN PTLSDBAllocateRequest pRequest,
IN BOOL fCheckAgreementType,
IN OUT PTLSDBLicenseAllocation pAllocated
)
/*
*/
{
DWORD status=ERROR_SUCCESS;
if(pDbWkSpace == NULL || pRequest == NULL || pAllocated == NULL)
{
DBGPrintf(
DBG_ERROR,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
DBG_ALL_LEVEL,
_TEXT("pDbWkSpace is NULL...\n")
);
SetLastError(status = ERROR_INVALID_PARAMETER);
TLSASSERT(FALSE);
return status;
}
status = VerifyTLSDBAllocateRequest(pRequest);
if(status != ERROR_SUCCESS)
return status;
if(pAllocated->dwBufSize <= 0)
{
DBGPrintf(
DBG_ERROR,
DBG_FACILITY_ALLOCATELICENSE,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("AllocateLicenses() invalid return buffer size\n")
);
SetLastError(status = TLS_E_INVALID_DATA);
return status;
}
#ifdef DBG
DWORD dwPrevNumLicense;
#endif
BOOL bProductInstalled=FALSE;
DWORD bufIndex=0;
TLSLICENSEPACK keypack_search;
TLSLICENSEPACK keypack_found;
DWORD dwNumLicenses = pRequest->dwNumLicenses; // number of license wanted/returned
DWORD dwTotalAllocated=0;
memset(&keypack_search, 0, sizeof(keypack_search));
memset(&keypack_found, 0, sizeof(keypack_found));
keypack_search.ucAgreementType = pRequest->ucAgreementType;
_tcscpy(keypack_search.szCompanyName, pRequest->szCompanyName);
_tcscpy(keypack_search.szProductId, pRequest->szProductId);
keypack_search.wMajorVersion = HIWORD(pRequest->dwVersion);
keypack_search.wMinorVersion = LOWORD(pRequest->dwVersion);
keypack_search.dwPlatformType = pRequest->dwPlatformId;
LicPackTable& licpack_table=pDbWkSpace->m_LicPackTable;
time_t current_time=time(NULL);
//
// Lock Key Pack table
// Only update requires locking, read might get in-correct value.
//
//
// Only allow one thread to enter - Jet not fast enough in updating entry
//
TLSDBLockKeyPackTable();
status = TLSDBKeyPackEnumBegin(
pDbWkSpace,
TRUE,
LSKEYPACK_SEARCH_PRODUCTID | (fCheckAgreementType ? LICENSEDPACK_FIND_LICENSEPACK : 0),
&keypack_search
);
if(status != ERROR_SUCCESS)
goto cleanup;
try {
while(status == ERROR_SUCCESS && dwNumLicenses != 0 && bufIndex < pAllocated->dwBufSize)
{
status = TLSDBKeyPackEnumNext(
pDbWkSpace,
&keypack_found
);
if(status != ERROR_SUCCESS)
break;
//
// Skip remote keypack
//
if(keypack_found.ucAgreementType & LSKEYPACK_REMOTE_TYPE)
{
continue;
}
if(keypack_found.ucKeyPackStatus & LSKEYPACKSTATUS_REMOTE)
{
continue;
}
if(fCheckAgreementType
&& (keypack_found.ucAgreementType != pRequest->ucAgreementType))
{
continue;
}
UCHAR ucKeyPackStatus = keypack_found.ucKeyPackStatus & ~LSKEYPACKSTATUS_RESERVED;
// Allocating licenses
//
// Throw away any key pack that has bad status
// one of the reason why can't returning license in this routine
// for returning license, we should not care about key pack
// status.
if(ucKeyPackStatus == LSKEYPACKSTATUS_UNKNOWN ||
ucKeyPackStatus == LSKEYPACKSTATUS_RETURNED ||
ucKeyPackStatus == LSKEYPACKSTATUS_REVOKED ||
ucKeyPackStatus == LSKEYPACKSTATUS_OTHERS)
{
continue;
}
//
// we find the product, make sure the version is what we want.
//
bProductInstalled=TRUE;
// Expired keypack
// TODO - update table here.
if((DWORD)keypack_found.dwExpirationDate < current_time)
continue;
//
// never allocate from older version
//
if( keypack_found.wMajorVersion < HIWORD(pRequest->dwVersion) )
{
continue;
}
//
// Same major version but older minor
//
if( keypack_found.wMajorVersion == HIWORD(pRequest->dwVersion) &&
keypack_found.wMinorVersion < LOWORD(pRequest->dwVersion) )
{
continue;
}
if(pRequest->dwScheme == ALLOCATE_EXACT_VERSION)
{
if(keypack_found.wMajorVersion != HIWORD(pRequest->dwVersion) ||
keypack_found.wMinorVersion < LOWORD(pRequest->dwVersion) )
{
continue;
}
}
UCHAR ucAgreementType = (keypack_found.ucAgreementType & ~LSKEYPACK_RESERVED_TYPE);
//
// Verify number of licenses left
//
if((ucAgreementType == LSKEYPACKTYPE_SELECT ||
ucAgreementType == LSKEYPACKTYPE_RETAIL ||
ucAgreementType == LSKEYPACKTYPE_CONCURRENT ||
ucAgreementType == LSKEYPACKTYPE_OPEN) &&
keypack_found.dwNumberOfLicenses == 0)
{
continue;
}
pAllocated->lpAllocateKeyPack[bufIndex] = keypack_found;
#ifdef DBG
dwPrevNumLicense = pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses;
#endif
if( ucAgreementType != LSKEYPACKTYPE_RETAIL &&
ucAgreementType != LSKEYPACKTYPE_CONCURRENT &&
ucAgreementType != LSKEYPACKTYPE_OPEN &&
ucAgreementType != LSKEYPACKTYPE_SELECT )
{
// For Free/temporary license, number of available license is
// how many license has been issued
pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses += dwNumLicenses;
pAllocated->pdwAllocationVector[bufIndex] = dwNumLicenses;
dwTotalAllocated += dwNumLicenses;
pAllocated->lpAllocateKeyPack[bufIndex].dwNextSerialNumber += dwNumLicenses;
dwNumLicenses=0;
}
else
{
int allocated=min(dwNumLicenses, keypack_found.dwNumberOfLicenses);
pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses -= allocated;
dwNumLicenses -= allocated;
pAllocated->pdwAllocationVector[bufIndex] = allocated;
dwTotalAllocated += allocated;
pAllocated->lpAllocateKeyPack[bufIndex].dwNextSerialNumber += allocated;
}
#if DBG
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_ALLOCATELICENSE,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("Updating keypack %d number of license from %d to %d\n"),
pAllocated->lpAllocateKeyPack[bufIndex].dwKeyPackId,
dwPrevNumLicense,
pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses
);
#endif
//
// Update number of licenses available for this keypack and license id in keypack
//
GetSystemTimeAsFileTime(&(pAllocated->lpAllocateKeyPack[bufIndex].ftLastModifyTime));
if(licpack_table.UpdateRecord(
pAllocated->lpAllocateKeyPack[bufIndex],
LICENSEDPACK_ALLOCATE_LICENSE_UPDATE_FIELD
) == FALSE)
{
SetLastError(status = SET_JB_ERROR(licpack_table.GetLastJetError()));
TLSASSERT(FALSE);
break;
}
#ifdef DBG
TLSLICENSEPACK test;
if(licpack_table.FetchRecord(test) == FALSE)
{
SetLastError(status = SET_JB_ERROR(licpack_table.GetLastJetError()));
TLSASSERT(FALSE);
}
if(test.dwKeyPackId != pAllocated->lpAllocateKeyPack[bufIndex].dwKeyPackId ||
test.dwNumberOfLicenses != pAllocated->lpAllocateKeyPack[bufIndex].dwNumberOfLicenses)
{
TLSASSERT(FALSE);
}
//FreeTlsLicensePack(&test);
#endif
bufIndex++;
}
}
catch(...)
{
SetLastError(status = TLS_E_INTERNAL);
}
//
// terminate enumeration.
//
TLSDBKeyPackEnumEnd(pDbWkSpace);
if(status == TLS_I_NO_MORE_DATA)
{
if(bufIndex != 0)
{
status = ERROR_SUCCESS;
}
else if(!bProductInstalled)
{
SetLastError(status = TLS_E_PRODUCT_NOTINSTALL);
}
}
pAllocated->dwBufSize = bufIndex;
pAllocated->dwTotalAllocated = dwTotalAllocated;
pAllocated->dwBufSize = bufIndex;
cleanup:
TLSDBUnlockKeyPackTable();
return status;
}