Windows-Server-2003/termsrv/license/lsreport/lsreport.cpp

708 lines
17 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999
//
// File: lsreport.cpp
//
// Contents: LSReport engine - complete back end
//
// History: 06-10-99 t-BStern Created
//
//---------------------------------------------------------------------------
#include "lsreport.h"
#include "lsrepdef.h"
#include <time.h>
#include <oleauto.h>
TCHAR noExpire[NOEXPIRE_LENGTH] = { 0 };
TCHAR header[HEADER_LENGTH] = { 0 };
TCHAR szTemp[TYPESTR_LENGTH] = { 0 };
TCHAR szActive[TYPESTR_LENGTH] = { 0 };
TCHAR szUpgrade[TYPESTR_LENGTH] = { 0 };
TCHAR szRevoked[TYPESTR_LENGTH] = { 0 };
TCHAR szPending[TYPESTR_LENGTH] = { 0 };
TCHAR szConcur[TYPESTR_LENGTH] = { 0 };
TCHAR szUnknown[TYPESTR_LENGTH] = { 0 };
//-----------------------------
DWORD
GetPageSize( VOID ) {
static DWORD dwPageSize = 0;
if ( !dwPageSize ) {
SYSTEM_INFO sysInfo = { 0 };
GetSystemInfo( &sysInfo ); // cannot fail.
dwPageSize = sysInfo.dwPageSize;
}
return dwPageSize;
}
/*++**************************************************************
NAME: MyVirtualAlloc
as Malloc, but automatically protects the last page of the
allocation. This simulates pageheap behavior without requiring
it.
MODIFIES: ppvData -- receives memory
TAKES: dwSize -- minimum amount of data to get
RETURNS: TRUE when the function succeeds.
FALSE otherwise.
LASTERROR: not set
Free with MyVirtualFree
**************************************************************--*/
BOOL
MyVirtualAlloc( IN DWORD dwSize,
OUT PVOID *ppvData )
{
PBYTE pbData;
DWORD dwTotalSize;
PVOID pvLastPage;
// ensure that we allocate one extra page
dwTotalSize = dwSize / GetPageSize();
if( dwSize % GetPageSize() ) {
dwTotalSize ++;
}
// this is the guard page
dwTotalSize++;
dwTotalSize *= GetPageSize();
// do the alloc
pbData = (PBYTE) VirtualAlloc( NULL, // don't care where
dwTotalSize,
MEM_COMMIT |
MEM_TOP_DOWN,
PAGE_READWRITE );
if ( pbData ) {
pbData += dwTotalSize;
// find the LAST page.
pbData -= GetPageSize();
pvLastPage = pbData;
// now, carve out a chunk for the caller:
pbData -= dwSize;
// last, protect the last page:
if ( VirtualProtect( pvLastPage,
1, // protect the page containing the last byte
PAGE_NOACCESS,
&dwSize ) ) {
*ppvData = pbData;
return TRUE;
}
VirtualFree( pbData, 0, MEM_RELEASE );
}
return FALSE;
}
VOID
MyVirtualFree( IN PVOID pvData )
{
VirtualFree( pvData, 0, MEM_RELEASE );
}
// Returns TRUE on success.
BOOL
InitLSReportStrings(VOID)
{
return (
LoadString(NULL, IDS_HEADER_TEXT, header, HEADER_LENGTH) &&
LoadString(NULL, IDS_NO_EXPIRE, noExpire, NOEXPIRE_LENGTH) &&
LoadString(NULL, IDS_TEMPORARY_LICENSE, szTemp, TYPESTR_LENGTH) &&
LoadString(NULL, IDS_ACTIVE_LICENSE, szActive, TYPESTR_LENGTH) &&
LoadString(NULL, IDS_UPGRADED_LICENSE, szUpgrade, TYPESTR_LENGTH) &&
LoadString(NULL, IDS_REVOKED_LICENSE, szRevoked, TYPESTR_LENGTH) &&
LoadString(NULL, IDS_PENDING_LICENSE, szPending, TYPESTR_LENGTH) &&
LoadString(NULL, IDS_CONCURRENT_LICENSE, szConcur, TYPESTR_LENGTH) &&
LoadString(NULL, IDS_UNKNOWN_LICENSE, szUnknown, TYPESTR_LENGTH)
);
}
typedef DWORD (WINAPI* PTLSGETLASTERRORFIXED) (
TLS_HANDLE hHandle,
LPTSTR *pszBuffer,
PDWORD pdwErrCode
);
RPC_STATUS
TryGetLastError(PCONTEXT_HANDLE hBinding,
LPTSTR *pszBuffer)
{
RPC_STATUS status;
DWORD dwErrCode;
HINSTANCE hModule = LoadLibrary(L"mstlsapi.dll");
if (hModule)
{
PTLSGETLASTERRORFIXED pfnGetLastErrorFixed = (PTLSGETLASTERRORFIXED) GetProcAddress(hModule,"TLSGetLastErrorFixed");
if (pfnGetLastErrorFixed)
{
status = pfnGetLastErrorFixed(hBinding,pszBuffer,&dwErrCode);
if(status == RPC_S_OK && dwErrCode == ERROR_SUCCESS && pszBuffer != NULL)
{
FreeLibrary(hModule);
return status;
}
}
FreeLibrary(hModule);
}
{
LPTSTR lpszError = NULL;
status = ERROR_NOACCESS;
try
{
if ( !MyVirtualAlloc( ( TLS_ERROR_LENGTH ) * sizeof( TCHAR ),
(PVOID*) &lpszError ) )
{
return RPC_S_OUT_OF_MEMORY;
}
DWORD uSize = TLS_ERROR_LENGTH ;
memset(lpszError, 0, ( TLS_ERROR_LENGTH ) * sizeof( TCHAR ));
status = TLSGetLastError(hBinding,uSize,lpszError,&dwErrCode);
if(status == RPC_S_OK && dwErrCode == ERROR_SUCCESS)
{
*pszBuffer = (LPTSTR)MIDL_user_allocate((TLS_ERROR_LENGTH+1)*sizeof(TCHAR));
if (NULL != *pszBuffer)
{
_tcscpy(*pszBuffer,lpszError);
}
}
}
catch (...)
{
status = ERROR_NOACCESS;
}
if(lpszError)
MyVirtualFree(lpszError);
}
return status;
}
// Given a keypack and a machine to connect to, read every license in that kp.
// Is not called directly.
DWORD
LicenseLoop(
IN FILE *OutFile,
IN LPWSTR szName, // who owns this keypack?
IN DWORD kpID, // which keypack
IN LPCTSTR szProductDesc,
IN BOOL bTempOnly,
IN const PSYSTEMTIME stStart,
IN const PSYSTEMTIME stEnd,
IN BOOL fUseLimits,
IN BOOL fHwid) // are the above 2 parms valid
{
TLS_HANDLE subHand;
DWORD dwStatus;
DWORD dwErrCode = ERROR_SUCCESS;
WCHAR *msg = NULL;
LSLicense lsl;
subHand = TLSConnectToLsServer(szName);
if (subHand == NULL)
{
// The machine suddenly went away.
ShowError(GetLastError(), NULL, TRUE);
dwErrCode = ERROR_BAD_CONNECT;
}
else
{
lsl.dwKeyPackId = kpID;
dwStatus = TLSLicenseEnumBegin(
subHand,
LSLICENSE_SEARCH_KEYPACKID,
TRUE,
&lsl,
&dwErrCode);
if (dwErrCode != ERROR_SUCCESS)
{
TryGetLastError(subHand, &msg);
if (NULL != msg)
{
_fputts(msg, stderr);
MIDL_user_free(msg);
}
return dwErrCode;
}
else if (dwStatus)
{
return dwStatus;
}
do {
dwStatus = TLSLicenseEnumNext(subHand, &lsl, &dwErrCode);
if ((dwStatus == RPC_S_OK) && (dwErrCode == ERROR_SUCCESS)) {
if ((lsl.ucLicenseStatus == LSLICENSE_STATUS_TEMPORARY) ||
!bTempOnly) { // Does it fit the temp. requirements?
// We want to print if at any of the following are true:
// a) There are no limits
// b) Issued between stStart and stEnd
// c) Expired between stStart and stEnd
// d) issued before stStart and expired after stEnd
if (!fUseLimits // case a
|| ((CompDate(lsl.ftIssueDate, stStart) >= 0) &&
(CompDate(lsl.ftIssueDate, stEnd) <= 0)) // case b
|| ((CompDate(lsl.ftExpireDate, stStart) >= 0) &&
(CompDate(lsl.ftExpireDate, stEnd) <= 0)) // case c
|| ((CompDate(lsl.ftIssueDate, stStart) <= 0) &&
(CompDate(lsl.ftExpireDate, stEnd) >= 0))) // case d
{
PrintLicense(szName, // print it.
&lsl,
szProductDesc,
OutFile,
fHwid);
} // end check cases
} // end check for temp license
} // end good getnext
} while ((dwStatus == RPC_S_OK) && (dwErrCode == ERROR_SUCCESS));
if (dwStatus != RPC_S_OK)
{
return ShowError(dwStatus, NULL, TRUE);
}
if (dwErrCode != LSERVER_I_NO_MORE_DATA)
{
TryGetLastError(subHand, &msg);
if (NULL != msg)
{
_fputts(msg, stderr);
MIDL_user_free(msg);
msg = NULL;
}
}
TLSLicenseEnumEnd(subHand, &dwErrCode);
if (dwErrCode != ERROR_SUCCESS)
{
TryGetLastError(subHand, &msg);
if (NULL != msg)
{
_fputts(msg, stderr);
MIDL_user_free(msg);
}
}
TLSDisconnectFromServer(subHand);
}
return dwErrCode;
}
// Given a machine to connect to, iterate through the keypacks.
// Is not called directly.
DWORD
KeyPackLoop(
IN FILE *OutFile,
IN LPWSTR szName, // machine to connect to
IN BOOL bTempOnly,
IN const PSYSTEMTIME stStart,
IN const PSYSTEMTIME stEnd,
IN BOOL fUseLimits,
IN BOOL fHwid) // do we care about the previous 2 parms?
{
TLS_HANDLE hand;
DWORD dwStatus, dwErrCode;
LSKeyPack lskpKeyPack;
TCHAR *msg = NULL;
hand = TLSConnectToLsServer(szName);
if (hand == NULL)
{
return GetLastError();
}
memset(&lskpKeyPack, 0, sizeof(lskpKeyPack));
lskpKeyPack.dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
dwStatus = TLSKeyPackEnumBegin(hand,
LSKEYPACK_SEARCH_ALL,
FALSE,
&lskpKeyPack,
&dwErrCode);
if (dwErrCode != ERROR_SUCCESS)
{
return dwErrCode;
}
if (dwStatus != RPC_S_OK)
{
return dwStatus;
}
do {
dwStatus = TLSKeyPackEnumNext(hand, &lskpKeyPack, &dwErrCode);
if ((dwStatus == RPC_S_OK) && (dwErrCode == ERROR_SUCCESS))
{
LicenseLoop(OutFile,
szName,
lskpKeyPack.dwKeyPackId,
lskpKeyPack.szProductDesc,
bTempOnly,
stStart,
stEnd,
fUseLimits,
fHwid);
}
} while ((dwStatus == RPC_S_OK) && (dwErrCode == ERROR_SUCCESS));
if (dwStatus != RPC_S_OK)
{
return ShowError(dwStatus, NULL, TRUE);
}
if (dwErrCode != LSERVER_I_NO_MORE_DATA)
{
TryGetLastError(hand, &msg);
if (NULL != msg)
{
_fputts(msg, stderr);
MIDL_user_free(msg);
msg = NULL;
}
}
TLSKeyPackEnumEnd(hand, &dwErrCode);
if (dwErrCode != ERROR_SUCCESS)
{
TryGetLastError(hand, &msg);
if (NULL != msg)
{
_fputts(msg, stderr);
MIDL_user_free(msg);
}
}
TLSDisconnectFromServer(hand);
return dwErrCode;
}
// If bTempOnly is FALSE, all licenses will be dumped to the file. Otherwise,
// only Temporary licenses will be written. This is the one function to call
// to do all of the program's magic.
DWORD
ExportLicenses(
IN FILE *OutFile, // must be opened for writing first
IN PServerHolder pshServers,
IN BOOL fTempOnly,
IN const PSYSTEMTIME stStart,
IN const PSYSTEMTIME stEnd,
IN BOOL fUseLimits,
IN BOOL fHwid) // are the above 2 parms valid?
{
DWORD i;
DWORD dwStatus;
DWORD dwRetVal = ERROR_SUCCESS;
_fputts(header, OutFile);
for (i = 0; i < pshServers->dwCount; i++) {
dwStatus = KeyPackLoop(OutFile,
pshServers->pszNames[i],
fTempOnly,
stStart,
stEnd,
fUseLimits,
fHwid);
if (dwStatus != ERROR_SUCCESS)
{
INT_PTR arg;
dwRetVal = dwStatus;
arg = (INT_PTR)pshServers->pszNames[i];
ShowError(IDS_BAD_LOOP, &arg, FALSE);
ShowError(dwStatus, NULL, TRUE);
}
}
if (dwRetVal == ERROR_SUCCESS)
{
// Show a success banner.
ShowError(ERROR_SUCCESS, NULL, TRUE);
}
return dwRetVal;
}
// Performs actual output. of must be open.
// Not called directly.
VOID
PrintLicense(
IN LPCWSTR szName, // server allocating this license
IN const LPLSLicense p,
IN LPCTSTR szProductDesc,
IN FILE *of,
IN BOOL fHwid)
{
// All of these are used solely to convert a time_t to a short date.
BSTR bszDate;
UDATE uDate;
DATE Date;
HRESULT hr;
LPTSTR szType;
TCHAR tc;
// server name
_fputts(szName, of);
// license ID and keypack ID
_ftprintf(of, _T("\t%d\t%d\t"),
p->dwLicenseId,
p->dwKeyPackId);
// license holder (machine)
_fputts(p->szMachineName, of);
_fputtc('\t', of);
// license requestor (username)
_fputts(p->szUserName, of);
_fputtc('\t', of);
// Print issue date in locale-appropriate way
UnixTimeToSystemTime((const time_t)p->ftIssueDate, &uDate.st);
hr = VarDateFromUdate(&uDate, 0, &Date);
if (S_OK != hr)
{
return;
}
hr = VarBstrFromDate(Date, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), VAR_DATEVALUEONLY, &bszDate);
if (S_OK != hr)
{
return;
}
_fputts(bszDate, of);
SysFreeString(bszDate);
_fputtc('\t', of);
// print either "No Expiration" or locale-nice expiration date
if (0x7FFFFFFF == p->ftExpireDate)
{
_fputts(noExpire, of);
}
else
{
UnixTimeToSystemTime((const time_t)p->ftExpireDate, &uDate.st);
hr = VarDateFromUdate(&uDate, 0, &Date);
if (S_OK != hr)
{
return;
}
hr = VarBstrFromDate(Date, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), VAR_DATEVALUEONLY, &bszDate);
if (S_OK != hr)
{
return;
}
_fputts(bszDate, of);
SysFreeString(bszDate);
}
_fputtc('\t', of);
// Assign the right kind of text for the type of license,
// and then print the license type.
switch (p->ucLicenseStatus) {
case LSLICENSE_STATUS_TEMPORARY:
szType = szTemp;
break;
case LSLICENSE_STATUS_ACTIVE:
szType = szActive;
break;
case LSLICENSE_STATUS_UPGRADED:
szType = szUpgrade;
break;
case LSLICENSE_STATUS_REVOKE:
szType = szRevoked;
break;
case LSLICENSE_STATUS_PENDING:
szType = szPending;
break;
case LSLICENSE_STATUS_CONCURRENT:
szType = szConcur;
break;
case LSLICENSE_STATUS_UNKNOWN:
// Fall through
default:
szType = szUnknown;
}
_fputts(szType, of);
_fputtc('\t', of);
// Print the description
_fputts(szProductDesc, of);
_fputtc('\t', of);
//Doughu: Representation algorithm
//We have only 36 informational chars I0 through I35 due to szHWID being TCHAR[37]
//and we have to represent this in client HWID format, which is:
//0xI0I10000I2I3, 0xI4I5I6I7I8I9I10I11, 0xI12I13I14I15I16I17I18I19, 0xI20I21I22I23I24I25I26I27, 0xI28I29I30I31I32I33I34I35
if (fHwid)
{
for (int i=0; (((tc=p->szHWID[i])!=NULL)&&(i<36)); i++)
{
//this if statement is for prepending 0x
if (i==0)
{
_fputtc('0', of);_fputtc('x', of);
}
_fputtc(tc,of);
//this if statement is for 4 zeroes that need to be print since they were masked
if (i==1)
{
_fputtc('0', of); _fputtc('0', of); _fputtc('0', of); _fputtc('0', of);
}
//this if statement is for I3, I11, I19 and I26 values where we put comma followed by space and 0x
if((((i+5)%8)==0) &&( i!=35))
{
_fputtc(',', of); _fputtc(' ', of); _fputtc('0', of); _fputtc('x', of);
}
}
_fputtc('\n', of);
}
else
{
_fputtc('\n', of);
}
}
// returns <0 if when is before st, ==0 if they are the same date, and
// >0 if when is after st.
int CompDate(
IN DWORD when, // treated as a time_t
IN const PSYSTEMTIME st)
{
time_t when_t;
//
// time_t is 64 bits in win64. Convert, being careful to sign extend.
//
when_t = (time_t)((LONG)(when));
struct tm *t = localtime(&when_t);
if ((t->tm_year+1900) < st->wYear) {
return -1;
}
if ((t->tm_year+1900) > st->wYear) {
return 1;
}
if ((t->tm_mon+1) < st->wMonth) {
return -1;
}
if ((t->tm_mon+1) > st->wMonth) {
return 1;
}
if (t->tm_mday < st->wDay) {
return -1;
}
if (t->tm_mday > st->wDay) {
return 1;
}
return 0;
}
// From the Platform SDK.
void
UnixTimeToFileTime(
IN time_t t,
OUT LPFILETIME pft)
{
// Note that LONGLONG is a 64-bit value
LONGLONG ll;
ll = Int32x32To64(t, 10000000) + 116444736000000000;
pft->dwLowDateTime = (DWORD)ll;
pft->dwHighDateTime = (DWORD)(ll >> 32);
}
// Also from the Platform SDK.
void
UnixTimeToSystemTime(
IN time_t t,
OUT LPSYSTEMTIME pst)
{
FILETIME ft;
FILETIME ftloc;
UnixTimeToFileTime(t, &ft);
FileTimeToLocalFileTime(&ft, &ftloc);
FileTimeToSystemTime(&ftloc, pst);
}