|
|
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corporation
//
// SYNOPSIS
//
// Defines all the non-COM DLL exports for the IAS core.
//
///////////////////////////////////////////////////////////////////////////////
#include <iascore.h>
#include <iasevent.h>
#include <iastlb.h>
#include <iasutil.h>
#include <varvec.h>
#include <resource.h>
#include <winsock2.h>
#include <svcguid.h>
#include <md5.h>
///////////////////////////////////////////////////////////////////////////////
//
// Audit Channel API
//
///////////////////////////////////////////////////////////////////////////////
// Global pointer to the audit channel.
IAuditSink* pAuditChannel = NULL;
HRESULT WINAPI IASReportEvent( DWORD dwEventID, DWORD dwNumStrings, DWORD dwDataSize, LPCWSTR* aszStrings, LPVOID pRawData ) { if (pAuditChannel == NULL) { return E_POINTER; }
return pAuditChannel->AuditEvent(dwEventID, dwNumStrings, dwDataSize, (wchar_t**)aszStrings, (byte*)pRawData); }
///////////////////////////////////////////////////////////////////////////////
//
// Thread Pool API
//
///////////////////////////////////////////////////////////////////////////////
#include <dispatcher.h>
// The global dispatcher object.
Dispatcher dispatcher;
BOOL WINAPI IASRequestThread(PIAS_CALLBACK pOnStart) { return dispatcher.requestThread(pOnStart); }
DWORD WINAPI IASSetMaxNumberOfThreads(DWORD dwNumberOfThreads) { return dispatcher.setMaxNumberOfThreads(dwNumberOfThreads); }
DWORD WINAPI IASSetMaxThreadIdle(DWORD dwMilliseconds) { return dispatcher.setMaxThreadIdle(dwMilliseconds); }
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// IASRegisterComponent
//
// DESCRIPTION
//
// Updates the registry entries for the specified component.
//
///////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI IASRegisterComponent( HINSTANCE hInstance, REFCLSID clsid, LPCWSTR szProgramName, LPCWSTR szComponent, DWORD dwRegFlags, REFGUID tlid, WORD wVerMajor, WORD wVerMinor, BOOL bRegister ) { //////////
// Create the registrar object.
//////////
CComPtr<IRegistrar> p; RETURN_ERROR(CoCreateInstance(CLSID_Registrar, NULL, CLSCTX_INPROC_SERVER, IID_IRegistrar, (void**)&p));
//////////
// Get the module file name for the component.
//////////
WCHAR szModule[MAX_PATH + 1]; DWORD numberChars = GetModuleFileNameW(hInstance, szModule, MAX_PATH + 1); if ((numberChars == 0) || (numberChars == MAX_PATH + 1)) { DWORD error = GetLastError(); return HRESULT_FROM_WIN32(error); }
//////////
// Get our module file name.
//////////
WCHAR szOurModule[MAX_PATH + 1] = L""; if (!GetModuleFileNameW(_Module.GetModuleInstance(), szOurModule, MAX_PATH + 1)) { DWORD error = GetLastError(); return HRESULT_FROM_WIN32(error); }
//////////
// Convert the GUID strings.
//////////
WCHAR szClsID[40], szLibID[40]; RETURN_ERROR(StringFromGUID2( clsid, szClsID, sizeof(szClsID) / sizeof(WCHAR)));
RETURN_ERROR(StringFromGUID2( tlid, szLibID, sizeof(szLibID) / sizeof(WCHAR)));
//////////
// Convert the version to a string.
//////////
WCHAR szMajor[7] = L""; wsprintfW(szMajor, L"%d", wVerMajor); WCHAR szMinor[7] = L""; wsprintfW(szMinor, L"%d", wVerMinor);
//////////
// Parse the bit flags.
//////////
PCWSTR szContext, szAttributes, szModel;
if (dwRegFlags & IAS_REGISTRY_LOCAL) { szContext = L"LocalServer32"; } else { szContext = L"InprocServer32"; }
if (dwRegFlags & IAS_REGISTRY_AUTO) { szAttributes = L"Programmable"; } else { szAttributes = L""; }
if (dwRegFlags & IAS_REGISTRY_BOTH) { szModel = L"Both"; } else if (dwRegFlags & IAS_REGISTRY_APT) { szModel = L"Apartment"; } else { szModel = L"Free"; }
//////////
// Add the replacement strings.
//////////
RETURN_ERROR(p->AddReplacement(L"MODULE", szModule)); RETURN_ERROR(p->AddReplacement(L"CLSID", szClsID)); RETURN_ERROR(p->AddReplacement(L"PROGRAM", szProgramName)); RETURN_ERROR(p->AddReplacement(L"COMPONENT", szComponent)); RETURN_ERROR(p->AddReplacement(L"TYPENAME", L" ")); RETURN_ERROR(p->AddReplacement(L"LIBID", szLibID)); RETURN_ERROR(p->AddReplacement(L"MAJORVER", szMajor)); RETURN_ERROR(p->AddReplacement(L"MINORVER", szMinor)); RETURN_ERROR(p->AddReplacement(L"CONTEXT", szContext)); RETURN_ERROR(p->AddReplacement(L"ATTRIBUTES", szAttributes)); RETURN_ERROR(p->AddReplacement(L"MODEL", szModel));
//////////
// Now we either register or unregister the component based on the
// bRegister flag.
//////////
HRESULT hr; if (bRegister) { hr = p->ResourceRegister(szOurModule, IDR_IASCOM, L"REGISTRY"); } else { hr = p->ResourceUnregister(szOurModule, IDR_IASCOM, L"REGISTRY"); }
return hr; }
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// IASAdler32
//
// DESCRIPTION
//
// Computes the Adler-32 checksum of a buffer.
//
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI IASAdler32( CONST BYTE *pBuffer, DWORD nBufferLength ) { static const DWORD ADLER_BASE = 65521;
DWORD s1 = 1; DWORD s2 = 0;
while (nBufferLength--) { s1 = (s1 + *pBuffer++) % ADLER_BASE;
s2 = (s2 + s1) % ADLER_BASE; }
return (s2 << 16) + s1; }
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// IASAllocateUniqueID
//
// DESCRIPTION
//
// Allocates a 32-bit integer that's guaranteed to be unique process-wide.
//
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI IASAllocateUniqueID( VOID ) { static LONG nextID = 0;
return (DWORD)InterlockedIncrement(&nextID); }
//////////
// Convert a hex digit to the number it represents.
//////////
inline BYTE digit2Num(WCHAR digit) throw () { return (digit >= L'0' && digit <= L'9') ? digit - L'0' : digit - (L'A' - 10); }
//////////
// Convert a number to a hex representation.
//////////
inline WCHAR num2Digit(BYTE num) throw () { return (num < 10) ? num + L'0' : num + (L'A' - 10); }
///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION
//
// IASVariantChangeType
//
// DESCRIPTION
//
// Replacement for VariantChangeType (q.v.) to bypass creating a message
// loop.
//
///////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI IASVariantChangeType( VARIANT * pvargDest, VARIANT * pvarSrc, USHORT wFlags, VARTYPE vt ) { // Check the input arguments.
if (pvargDest == NULL || pvarSrc == NULL) { return E_INVALIDARG; }
// Is the source already the requested type?
if (V_VT(pvarSrc) == vt) { return (pvargDest != pvarSrc) ? VariantCopy(pvargDest, pvarSrc) : S_OK; }
VARIANT varTmp; VariantInit(&varTmp);
switch (MAKELONG(vt, V_VT(pvarSrc))) { case MAKELONG(VT_BOOL, VT_BSTR): { if (V_BSTR(pvarSrc) == NULL) { return DISP_E_TYPEMISMATCH; } V_BOOL(&varTmp) = (VARIANT_BOOL) _wtol(V_BSTR(pvarSrc)) ? VARIANT_TRUE : VARIANT_FALSE; break; }
case MAKELONG(VT_I4, VT_BSTR): { if (V_BSTR(pvarSrc) == NULL) { return DISP_E_TYPEMISMATCH; } V_I4(&varTmp) = _wtol(V_BSTR(pvarSrc)); break; }
case MAKELONG((VT_UI1 | VT_ARRAY) , VT_BSTR): { // Extract the source string.
PCWSTR src = V_BSTR(pvarSrc); if (src == NULL) { return DISP_E_TYPEMISMATCH; } LONG srclen = wcslen(src);
// Compute the destination length.
if (srclen & 1) { return DISP_E_TYPEMISMATCH; } LONG dstlen = srclen / 2;
// Allocate a SAFEARRAY of bytes to hold the octets.
CVariantVector<BYTE> vec(&varTmp, dstlen); PBYTE dst = vec.data();
// Loop through the source and convert.
while (dstlen--) { *dst = digit2Num(*src++) << 4; *dst++ |= digit2Num(*src++); }
break; }
case MAKELONG(VT_BSTR, VT_BOOL): { V_BSTR(&varTmp) = SysAllocString(V_BOOL(pvarSrc) ? L"-1" : L"0"); if (V_BSTR(&varTmp) == NULL) { return E_OUTOFMEMORY; } break; }
case MAKELONG(VT_BSTR, VT_I4): { WCHAR buffer[12]; V_BSTR(&varTmp) = SysAllocString(_ltow(V_I4(pvarSrc), buffer, 10)); if (V_BSTR(&varTmp) == NULL) { return E_OUTOFMEMORY; } break; }
case MAKELONG(VT_BSTR, (VT_UI1 | VT_ARRAY)): { // Extract the source octets.
CVariantVector<BYTE> vec(pvarSrc); CONST BYTE* src = vec.data(); LONG srclen = vec.size();
// Allocate space for the 'stringized' version.
PWCHAR dst = SysAllocStringLen(NULL, srclen * 2); if (dst == NULL) { return E_OUTOFMEMORY; } V_BSTR(&varTmp) = dst;
// Loop through and convert.
while (srclen--) { *dst++ = num2Digit(*src >> 4); *dst++ = num2Digit(*src++ & 0xF); }
// Add a null-terminator.
*dst = L'\0'; break; }
default: return DISP_E_TYPEMISMATCH; }
// We successfully converted, so set the type.
V_VT(&varTmp) = vt;
// Free the destination.
VariantClear(pvargDest);
// Copy in the coerced variant.
*pvargDest = varTmp;
return S_OK; }
///////////////////////////////////////////////////////////////////////////////
//
// Routines to handle startup and shutdown.
//
///////////////////////////////////////////////////////////////////////////////
// Reference count for the IAS API.
LONG refCount = 0;
// Shared local dictionary.
VARIANT theDictionaryStorage;
BOOL WINAPI IASInitialize(VOID) { HRESULT hr; DWORD error; WSADATA wsaData;
// Global lock to serialize access.
IASGlobalLockSentry sentry;
// If we're already initialized, there's nothing to do.
if (refCount > 0) { ++refCount; return TRUE; }
// Initialize the audit channel.
hr = CoCreateInstance(__uuidof(AuditChannel), NULL, CLSCTX_INPROC_SERVER, __uuidof(IAuditSink), (PVOID*)&pAuditChannel); if (FAILED(hr)) { SetLastError(hr); goto auditor_failed; }
// Initialize winsock.
error = WSAStartup(MAKEWORD(2, 0), &wsaData); if (error) { SetLastError(error); goto wsa_failed; }
// Initialize the thread pool.
if (!dispatcher.initialize()) { goto thrdpool_failed; }
// Everything succeeded, so bump up the refCount.
++refCount; return TRUE;
thrdpool_failed: WSACleanup();
wsa_failed: pAuditChannel->Release(); pAuditChannel = NULL;
auditor_failed: return FALSE; }
VOID WINAPI IASUninitialize( VOID) { IASGlobalLockSentry sentry;
_ASSERT(refCount != 0);
if (--refCount == 0) { // Shutdown the thread pool. This blocks until all threads have exited.
dispatcher.finalize();
// Shutdown winsock.
WSACleanup();
// Shutdown the audit channel.
pAuditChannel->Release(); pAuditChannel = NULL;
// Shutdown the dictionary.
VariantClear(&theDictionaryStorage); } }
VOID WINAPI IASRadiusCrypt( BOOL encrypt, BOOL salted, const BYTE* secret, ULONG secretLen, const BYTE* reqAuth, PBYTE buf, ULONG buflen ) { MD5_CTX context; BYTE cipherText[MD5DIGESTLEN]; BYTE *p; const BYTE *end, *endBlock, *ct, *src; WORD salt; static LONG theNextSalt;
// Use the Request-Authenticator as the first block of ciphertext.
ct = reqAuth;
// Compute the beginning and end of the data to be crypted.
p = buf; end = buf + buflen;
// Is the buffer salted ?
if (salted) { if (encrypt) { // Get the next salt value.
salt = (WORD)(++theNextSalt); // High bit must be set.
salt |= 0x8000; // Store at the front of the buffer.
IASInsertWORD(buf, salt); }
// Skip past the salt.
p += 2; }
// Loop through the buffer.
while (p < end) { // Compute the digest.
MD5Init(&context); MD5Update(&context, secret, secretLen); MD5Update(&context, ct, MD5DIGESTLEN); if (salted) { MD5Update(&context, buf, 2); // Only use the salt on the first pass.
salted = FALSE; } MD5Final(&context);
// Find the end of the block to be decrypted.
endBlock = p + MD5DIGESTLEN; if (endBlock >= end) { // We've reached the end of the buffer.
endBlock = end; } else { // Save the ciphertext for the next pass.
ct = encrypt ? p : (PBYTE)memcpy(cipherText, p, MD5DIGESTLEN); }
// Crypt the block.
for (src = context.digest; p < endBlock; ++p, ++src) { *p ^= *src; } } }
/////////
// Unicode version of gethostbyname. The caller must free the returned hostent
// struct by calling LocalFree.
/////////
PHOSTENT WINAPI IASGetHostByName( IN PCWSTR name ) { // We put these at function scope, so we can clean them up on the way out.
DWORD error = NO_ERROR; HANDLE lookup = NULL; union { WSAQUERYSETW querySet; BYTE buffer[512]; }; PWSAQUERYSETW result = NULL; PHOSTENT retval = NULL;
do { if (!name) { // A NULL name means use the local host, so allocate a buffer ...
DWORD size = 0; GetComputerNameEx( ComputerNamePhysicalDnsFullyQualified, NULL, &size ); PWSTR buf = (PWSTR)_alloca(size * sizeof(WCHAR));
// ... and get the local DNS name.
if (!GetComputerNameEx( ComputerNamePhysicalDnsFullyQualified, buf, &size )) { error = GetLastError(); break; }
name = buf; }
//////////
// Create the query set
//////////
GUID hostAddrByNameGuid = SVCID_INET_HOSTADDRBYNAME; AFPROTOCOLS protocols[2] = { { AF_INET, IPPROTO_UDP }, { AF_INET, IPPROTO_TCP } }; memset(&querySet, 0, sizeof(querySet)); querySet.dwSize = sizeof(querySet); querySet.lpszServiceInstanceName = (PWSTR)name; querySet.lpServiceClassId = &hostAddrByNameGuid; querySet.dwNameSpace = NS_ALL; querySet.dwNumberOfProtocols = 2; querySet.lpafpProtocols = protocols;
//////////
// Execute the query.
//////////
error = WSALookupServiceBeginW( &querySet, LUP_RETURN_ADDR, &lookup ); if (error) { error = WSAGetLastError(); break; }
//////////
// How much space do we need for the result?
//////////
DWORD length = sizeof(buffer); error = WSALookupServiceNextW( lookup, 0, &length, &querySet ); if (!error) { result = &querySet; } else { error = WSAGetLastError(); if (error != WSAEFAULT) { break; }
/////////
// Allocate memory to hold the result.
/////////
result = (PWSAQUERYSETW)LocalAlloc(0, length); if (!result) { error = WSA_NOT_ENOUGH_MEMORY; break; }
/////////
// Get the result.
/////////
error = WSALookupServiceNextW( lookup, 0, &length, result ); if (error) { error = WSAGetLastError(); break; } }
if (result->dwNumberOfCsAddrs == 0) { error = WSANO_DATA; break; }
///////
// Allocate memory to hold the hostent struct
///////
DWORD naddr = result->dwNumberOfCsAddrs; SIZE_T nbyte = sizeof(hostent) + (naddr + 1) * sizeof(char*) + naddr * sizeof(in_addr); retval = (PHOSTENT)LocalAlloc(0, nbyte); if (!retval) { error = WSA_NOT_ENOUGH_MEMORY; break; }
///////
// Initialize the hostent struct.
///////
retval->h_name = NULL; retval->h_aliases = NULL; retval->h_addrtype = AF_INET; retval->h_length = sizeof(in_addr); retval->h_addr_list = (char**)(retval + 1);
///////
// Store the addresses.
///////
u_long* nextAddr = (u_long*)(retval->h_addr_list + naddr + 1);
for (DWORD i = 0; i < naddr; ++i) { sockaddr_in* sin = (sockaddr_in*) result->lpcsaBuffer[i].RemoteAddr.lpSockaddr;
retval->h_addr_list[i] = (char*)nextAddr;
*nextAddr++ = sin->sin_addr.S_un.S_addr; }
///////
// NULL terminate the address list.
///////
retval->h_addr_list[i] = NULL;
} while (FALSE);
//////////
// Clean up and return.
//////////
if (result && result != &querySet) { LocalFree(result); }
if (lookup) { WSALookupServiceEnd(lookup); }
if (error) { if (error == WSASERVICE_NOT_FOUND) { error = WSAHOST_NOT_FOUND; }
WSASetLastError(error); }
return retval; }
/////////
// Fill in an IASTable struct from a VARIANT containing the table data.
/////////
HRESULT ExtractTableFromVariant( IN VARIANT* var, OUT IASTable* table ) throw () { // Check the arguments.
if (!var || !table) { return E_POINTER; }
// Outer VARIANT must be an array of VARIANTs.
if (V_VT(var) != (VT_ARRAY | VT_VARIANT)) { return E_INVALIDARG; }
// Array must be 1D with exactly 3 elements.
LPSAFEARRAY array = V_ARRAY(var); if (array->cDims != 1 || array->rgsabound[0].cElements != 3) { return E_INVALIDARG; }
// tableData is an array of three variants:
// (1) Column names
// (2) Column types.
// (3) Table data matrix.
VARIANT* tableData = (VARIANT*)(array->pvData);
// Process the column names.
VARIANT* namesVariant = tableData + 0;
// The VARIANT must be an array of BSTRs.
if (V_VT(namesVariant) != (VT_ARRAY | VT_BSTR)) { return E_INVALIDARG; }
// Array must be 1D.
LPSAFEARRAY namesArray = V_ARRAY(namesVariant); if (namesArray->cDims != 1) { return E_INVALIDARG; }
// Store the info in the IASTable.
table->numColumns = namesArray->rgsabound[0].cElements; table->columnNames = (BSTR*)(namesArray->pvData);
// Process the column types.
VARIANT* typesVariant = tableData + 1;
// The VARIANT must be an array of shorts.
if (V_VT(typesVariant) != (VT_ARRAY | VT_UI2)) { return E_INVALIDARG; }
// Array must be 1D with 1 element per column.
LPSAFEARRAY typesArray = V_ARRAY(typesVariant); if (typesArray->cDims != 1 || typesArray->rgsabound[0].cElements != table->numColumns) { return E_INVALIDARG; }
// Store the info in the IASTable.
table->columnTypes = (VARTYPE*)(namesArray->pvData);
// Process the table data matrix.
VARIANT* tableVariant = tableData + 2;
// The VARIANT must be an array of VARIANTs.
if (V_VT(tableVariant) != (VT_ARRAY | VT_VARIANT)) { return E_INVALIDARG; }
// Array must be 2D with 1st dim equal to number of columns.
LPSAFEARRAY tableArray = V_ARRAY(tableVariant); if (tableArray->cDims != 2 || tableArray->rgsabound[0].cElements != table->numColumns) { return E_INVALIDARG; }
// Store the info in the IASTable.
table->numRows = tableArray->rgsabound[1].cElements; table->table = (VARIANT*)(tableArray->pvData);
return S_OK; }
HRESULT WINAPI IASGetDictionary( IN PCWSTR path, OUT IASTable* dnary, OUT VARIANT* storage ) { // Initialize the out parameters.
VariantInit(storage);
// Create the AttributeDictionary object.
HRESULT hr; CComPtr<IAttributeDictionary> dnaryObj; hr = CoCreateInstance( __uuidof(AttributeDictionary), NULL, CLSCTX_SERVER, __uuidof(IAttributeDictionary), (PVOID*)&dnaryObj ); if (FAILED(hr)) { return hr; }
// We need to give the object permission to impersonate us. There's
// no reason to abort if this fails; we'll just try with the
// existing blanket.
CoSetProxyBlanket( dnaryObj, RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DEFAULT );
// Convert the path to a BSTR.
CComBSTR bstrPath(path); if (!bstrPath) { return E_OUTOFMEMORY; }
// Get the dictionary.
hr = dnaryObj->GetDictionary(bstrPath, storage); if (FAILED(hr)) { return hr; }
hr = ExtractTableFromVariant(storage, dnary); if (FAILED(hr)) { VariantClear(storage); }
return hr; }
const IASTable* WINAPI IASGetLocalDictionary( VOID ) { static IASTable theTable;
// Global lock to serialize access.
IASGlobalLockSentry sentry;
// Have we already gotten the local dictionary ?
if (V_VT(&theDictionaryStorage) == VT_EMPTY) { HRESULT hr;
// No, so determine the path ...
WCHAR path[256]; DWORD size = sizeof(path)/sizeof(WCHAR); hr = IASGetDictionaryPath(path, &size); if (hr == NO_ERROR) { // ... and get the dictionary.
hr = IASGetDictionary( path, &theTable, &theDictionaryStorage ); } else { hr = HRESULT_FROM_WIN32(hr); }
if (FAILED(hr)) { SetLastError(hr); return NULL; } }
return &theTable; }
CRITICAL_SECTION theGlobalLock;
VOID WINAPI IASGlobalLock() { EnterCriticalSection(&theGlobalLock); }
VOID WINAPI IASGlobalUnlock() { LeaveCriticalSection(&theGlobalLock); }
namespace { // The registry value used to store the license type.
const wchar_t licenseTypeValue[] = L"LicenseType"; }
DWORD WINAPI IASGetLicenseType( OUT IAS_LICENSE_TYPE* licenseType ) { if (licenseType == 0) { return ERROR_INVALID_PARAMETER; }
OSVERSIONINFOEXW versionInfo; memset(&versionInfo, 0, sizeof(versionInfo)); versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); if (!GetVersionExW(reinterpret_cast<OSVERSIONINFOW*>(&versionInfo))) { return GetLastError(); }
if (versionInfo.wProductType == VER_NT_WORKSTATION) { if ((versionInfo.wSuiteMask & VER_SUITE_PERSONAL) != 0) { *licenseType = IASLicenseTypePersonal; } else { *licenseType = IASLicenseTypeProfessional; } } else { if ((versionInfo.wSuiteMask & VER_SUITE_DATACENTER) != 0) { *licenseType = IASLicenseTypeDataCenter; } else if ((versionInfo.wSuiteMask & VER_SUITE_ENTERPRISE) != 0) { *licenseType = IASLicenseTypeEnterpriseServer; } else if ((versionInfo.wSuiteMask & VER_SUITE_BLADE) != 0) { *licenseType = IASLicenseTypeWebBlade; } else if ((versionInfo.wSuiteMask & VER_SUITE_SMALLBUSINESS) != 0) { *licenseType = IASLicenseTypeSmallBusinessServer; } else { *licenseType = IASLicenseTypeStandardServer; } }
return NO_ERROR; }
DWORD WINAPI IASPublishLicenseType( IN HKEY hKey ) { IAS_LICENSE_TYPE licenseType; DWORD error = IASGetLicenseType(&licenseType); if (error == NO_ERROR) { DWORD value = licenseType; error = RegSetValueEx( hKey, licenseTypeValue, 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value) ); }
return error; }
DWORD WINAPI IASGetProductLimits( IN LPCWSTR computerName, OUT IAS_PRODUCT_LIMITS* limits ) { DWORD error; IAS_LICENSE_TYPE licenseType;
if (computerName != 0) { CRegKey remote; error = RegConnectRegistryW( computerName, HKEY_LOCAL_MACHINE, &(remote.m_hKey) ); if (error != NO_ERROR) { return error; }
CRegKey policy; error = policy.Open(remote, IAS_POLICY_KEY); if (error != NO_ERROR) { return error; }
DWORD value; error = policy.QueryValue(value, licenseTypeValue); if (error == NO_ERROR) { licenseType = static_cast<IAS_LICENSE_TYPE>(value); } else if (error == ERROR_FILE_NOT_FOUND) { // If the value doesn't exist, assume this is a downlevel machine
// since we didn't create this value before .NET Server.
licenseType = IASLicenseTypeDownlevel; } else { return error; } } else { error = IASGetLicenseType(&licenseType); if (error != NO_ERROR) { return error; } }
return IASGetProductLimitsForType(licenseType, limits); }
VOID WINAPI IASReportLicenseViolation( VOID ) { IASReportEvent(IAS_E_SERVICE_LICENSE_VIOLATION, 0, 0, 0, 0); }
|