//+-------------------------------------------------------------------------- // // 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 #include 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); }