836 lines
19 KiB
C++
836 lines
19 KiB
C++
/*
|
|
** Copyright (c) 1998 Microsoft Corporation
|
|
** All Rights Reserved
|
|
**
|
|
**
|
|
*/
|
|
#include <windows.h>
|
|
#include <objbase.h>
|
|
#include <winbase.h>
|
|
#include <wchar.h>
|
|
|
|
// Required by SSPI.H
|
|
#define SECURITY_WIN32
|
|
#include <sspi.h>
|
|
|
|
#include <dsgetdc.h>
|
|
#include <ntdsapi.h>
|
|
#include <lmcons.h>
|
|
#include <lmapibuf.h>
|
|
#include <activeds.h>
|
|
#include "lscommon.h"
|
|
#include "tlsrpc.h"
|
|
#include "tlsapi.h"
|
|
#include "tlsapip.h"
|
|
|
|
#define CWSTR_SIZE(x) (sizeof(x) - (sizeof(WCHAR) * 2))
|
|
#define DWSTR_SIZE(x) ((wcslen(x) + 1) * sizeof(WCHAR))
|
|
|
|
#define LICENSE_SETTINGS L"TS-Enterprise-License-Server"
|
|
#define LICENSE_SETTINGS_FORMAT L"LDAP://CN=%ws,CN=%ws,CN=%ws,%ws"
|
|
#define LICENSE_SETTINGS_SIZE CWSTR_SIZE(LICENSE_SETTINGS)
|
|
#define LICENSE_SETTINGS_FORMAT_SIZE CWSTR_SIZE(LICENSE_SETTINGS_FORMAT)
|
|
#define SITES L"sites"
|
|
#define SITES_SIZE CWSTR_SIZE(SITES)
|
|
#define CONFIG_CNTNR L"ConfigurationNamingContext"
|
|
#define CONFIG_CNTNR_FORMAT L"LDAP://CN=%ws,%ws"
|
|
#define CONFIG_CNTNR_FORMAT_SIZE CWSTR_SIZE(CONFIG_CNTNR_FORMAT)
|
|
#define ROOT_DSE_PATH L"LDAP://RootDSE"
|
|
#define ADS_PATH L"ADsPath"
|
|
#define SEARCH_FILTER L"(CN=TS-Enterprise-LicenseServer)"
|
|
#define DNS_MACHINE_NAME L"dNSHostName"
|
|
#define IS_DELETED L"isDeleted"
|
|
#define SITE_SERVER L"siteServer"
|
|
|
|
HRESULT GetLicenseServersFromReg(LPWSTR wszRegKey, LPWSTR *ppwszServerNames,DWORD *pcServers, LPWSTR **prgwszServers);
|
|
|
|
HRESULT
|
|
WriteLicenseServersToReg(LPWSTR wszRegKey, LPWSTR pwszServerNames,DWORD cchServers);
|
|
|
|
extern BOOL g_fInDomain;
|
|
|
|
extern "C" DWORD WINAPI
|
|
TLSDisconnect(
|
|
TLS_HANDLE* pphContext
|
|
);
|
|
|
|
//
|
|
// Pre-fill the ADSI cache with only the attribute we want, then get it
|
|
// Only use if exactly one attribute is needed
|
|
//
|
|
|
|
HRESULT
|
|
GetWithGetInfoEx(
|
|
IADs *pADs,
|
|
LPWSTR wszAttribute,
|
|
VARIANT *pvar
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = ADsBuildVarArrayStr( &wszAttribute, 1, pvar );
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
hr = pADs->GetInfoEx( *pvar, 0L );
|
|
VariantClear( pvar );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pADs->Get( wszAttribute, pvar );
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Pre-fill the ADSI cache with only the attributes we want, then get them
|
|
// Only use if exactly two attributes are needed
|
|
//
|
|
|
|
HRESULT
|
|
GetWithGetInfoEx2(
|
|
IADs *pADs,
|
|
LPWSTR wszAttribute1,
|
|
LPWSTR wszAttribute2,
|
|
VARIANT *pvar1,
|
|
VARIANT *pvar2,
|
|
HRESULT *phr2
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
LPWSTR rgwszAttributes[] = {wszAttribute1,wszAttribute2};
|
|
|
|
hr = ADsBuildVarArrayStr( rgwszAttributes, 2, pvar1 );
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
hr = pADs->GetInfoEx( *pvar1, 0L );
|
|
VariantClear( pvar1 );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pADs->Get( wszAttribute1, pvar1 );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*phr2 = pADs->Get( wszAttribute2, pvar2 );
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
GetExWithGetInfoEx(
|
|
IADs *pADs,
|
|
LPWSTR wszAttribute,
|
|
VARIANT *pvar
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = ADsBuildVarArrayStr( &wszAttribute, 1, pvar );
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
hr = pADs->GetInfoEx( *pvar, 0L );
|
|
VariantClear( pvar );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pADs->GetEx( wszAttribute, pvar );
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetLicenseSettingsObject(VARIANT *pvar,
|
|
LPWSTR *ppwszLicenseSettings,
|
|
LPWSTR *ppwszSiteName,
|
|
IADs **ppADs)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwErr = 0;
|
|
LPWSTR pwszConfigContainer;
|
|
IADs * pADs = NULL;
|
|
IDirectorySearch *pADsSearch = NULL;
|
|
ADS_SEARCH_HANDLE hSearch = NULL;
|
|
ADS_SEARCH_COLUMN Column;
|
|
LPWSTR pwszAdsPath = ADS_PATH;
|
|
LPWSTR pwszSitesPath = NULL;
|
|
BOOL fInDomain;
|
|
|
|
if (g_fInDomain == -1)
|
|
{
|
|
dwErr = TLSInDomain(&fInDomain,NULL);
|
|
if (dwErr != NO_ERROR)
|
|
return HRESULT_FROM_WIN32(dwErr);
|
|
} else
|
|
{
|
|
fInDomain = g_fInDomain;
|
|
}
|
|
|
|
if (!fInDomain)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN);
|
|
}
|
|
|
|
VariantInit(pvar);
|
|
|
|
//
|
|
// Obtain the path to the configuration container.
|
|
//
|
|
|
|
hr = ADsGetObject(ROOT_DSE_PATH, IID_IADs, (void **)&pADs);
|
|
|
|
if (FAILED(hr)) {
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"ADsGetObject ROOT_DSE_PATH failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr = pADs->Get(CONFIG_CNTNR, pvar);
|
|
|
|
if (FAILED(hr)) {
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"Get CONFIG_CNTNR failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
if (V_VT(pvar) != VT_BSTR) {
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"bad variant 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
pwszConfigContainer = pvar->bstrVal; // For sake of readability.
|
|
|
|
//
|
|
// Get the site name, if possible
|
|
//
|
|
|
|
dwErr = DsGetSiteName(NULL, ppwszSiteName);
|
|
|
|
if (dwErr == 0)
|
|
{
|
|
//
|
|
// Build the X.500 path to the LicenseSettings object.
|
|
//
|
|
|
|
*ppwszLicenseSettings =
|
|
(LPWSTR)LocalAlloc(
|
|
LPTR,
|
|
LICENSE_SETTINGS_FORMAT_SIZE
|
|
+ LICENSE_SETTINGS_SIZE
|
|
+ DWSTR_SIZE(*ppwszSiteName)
|
|
+ SITES_SIZE
|
|
+ DWSTR_SIZE(pwszConfigContainer)
|
|
+ sizeof(TCHAR));
|
|
|
|
if (*ppwszLicenseSettings == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto CleanExit;
|
|
}
|
|
|
|
swprintf(*ppwszLicenseSettings,
|
|
LICENSE_SETTINGS_FORMAT,
|
|
LICENSE_SETTINGS,
|
|
*ppwszSiteName,
|
|
SITES,
|
|
pwszConfigContainer);
|
|
|
|
hr = ADsGetObject(*ppwszLicenseSettings, IID_IADs, (void **)ppADs);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// return this object
|
|
goto CleanExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// None in our site (or we don't know our site)
|
|
// Search all sites in GC, take first one
|
|
//
|
|
|
|
pwszSitesPath =
|
|
(LPWSTR)LocalAlloc(
|
|
LPTR,
|
|
CONFIG_CNTNR_FORMAT_SIZE
|
|
+ SITES_SIZE
|
|
+ DWSTR_SIZE(pwszConfigContainer)
|
|
+ sizeof(TCHAR));
|
|
|
|
if (pwszSitesPath == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto CleanExit;
|
|
}
|
|
|
|
swprintf(pwszSitesPath,
|
|
CONFIG_CNTNR_FORMAT,
|
|
SITES,
|
|
pwszConfigContainer);
|
|
|
|
hr = ADsGetObject(pwszSitesPath,
|
|
IID_IDirectorySearch,
|
|
(void **)&pADsSearch);
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"ADsGetObject ConfigContainer (%s) failed 0x%lx\n",pwszConfigContainer,hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr = pADsSearch->ExecuteSearch(SEARCH_FILTER,&pwszAdsPath,1,&hSearch);
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"ExecuteSearch failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr = pADsSearch->GetNextRow(hSearch);
|
|
|
|
if (hr == S_ADS_NOMORE_ROWS)
|
|
hr = E_ADS_PROPERTY_NOT_SET;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"GetNextRow failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr = pADsSearch->GetColumn(hSearch,pwszAdsPath,&Column);
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"GetColumn (%ws) failed 0x%lx\n",pwszAdsPath,hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr = ADsGetObject(Column.pADsValues->CaseIgnoreString,
|
|
IID_IADs,
|
|
(void **)ppADs);
|
|
|
|
pADsSearch->FreeColumn(&Column);
|
|
|
|
CleanExit:
|
|
if (NULL != pADs) {
|
|
pADs->Release();
|
|
}
|
|
|
|
if (NULL != pADsSearch) {
|
|
if (hSearch != NULL) {
|
|
pADsSearch->CloseSearchHandle(hSearch);
|
|
}
|
|
|
|
pADsSearch->Release();
|
|
}
|
|
|
|
if (NULL != pwszSitesPath)
|
|
{
|
|
LocalFree(pwszSitesPath);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
GetRandomServer(IADs *pADs,
|
|
VARIANT *pvar
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
VARIANT var;
|
|
SAFEARRAY *psaServers;
|
|
LONG lLower, lUpper, lPos;
|
|
|
|
VariantInit(&var);
|
|
|
|
hr = GetExWithGetInfoEx(pADs,SITE_SERVER,&var);
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"GetEx (%ws) failed 0x%lx\n",LICENSE_SETTINGS,hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
psaServers = V_ARRAY(&var);
|
|
if (NULL == psaServers)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"GetEx no array failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr= SafeArrayGetLBound( psaServers, 1, &lLower );
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"SafeArrayGetLBound failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr= SafeArrayGetUBound( psaServers, 1, &lUpper );
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"SafeArrayGetUBound failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
srand(GetTickCount());
|
|
|
|
lPos = (rand() % (lUpper - lLower + 1)) + lLower;
|
|
|
|
hr = SafeArrayGetElement( psaServers, &lPos, pvar );
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"SafeArrayGetElement (%d) failed? 0x%lx\n",lPos,hr);
|
|
#endif
|
|
|
|
CleanExit:
|
|
VariantClear(&var);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
GetAllServers(IADs *pADs,
|
|
VARIANT *pvar
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = GetExWithGetInfoEx(pADs,SITE_SERVER,pvar);
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"GetEx (%ws) failed 0x%lx\n",LICENSE_SETTINGS,hr);
|
|
#endif
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
DnToFqdn(LPWSTR pwszDN, LPWSTR pwszFqdn)
|
|
{
|
|
LPWSTR pwszBindPath;
|
|
HRESULT hr, hr2;
|
|
IADs * pADs2 = NULL;
|
|
VARIANT var2;
|
|
VARIANT var3;
|
|
|
|
VariantInit(&var2);
|
|
VariantInit(&var3);
|
|
|
|
//
|
|
// Bind to the computer object referenced by the Site-Server property.
|
|
//
|
|
|
|
// LDAP:// + pwszDN + 1
|
|
pwszBindPath = (LPWSTR) LocalAlloc(LPTR,
|
|
(wcslen(pwszDN) + 8) * sizeof(WCHAR));
|
|
|
|
if (pwszBindPath == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"LocalAlloc failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
wsprintf(pwszBindPath, L"LDAP://%ws", pwszDN);
|
|
|
|
hr = ADsOpenObject(pwszBindPath,
|
|
NULL,
|
|
NULL,
|
|
ADS_SERVER_BIND,
|
|
IID_IADs,
|
|
(void **)&pADs2);
|
|
|
|
LocalFree(pwszBindPath);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"ADsOpenObject failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// Fetch the Machine-DNS-Name property.
|
|
//
|
|
|
|
hr = GetWithGetInfoEx2(pADs2,DNS_MACHINE_NAME, IS_DELETED, &var3, &var2, &hr2);
|
|
|
|
if (FAILED(hr)) {
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"Get failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
if (SUCCEEDED(hr2))
|
|
{
|
|
hr = VariantChangeType(&var2,&var2,0,VT_BOOL);
|
|
|
|
if (FAILED(hr)) {
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"VariantChangeType failed 0x%lx\n",hr);
|
|
#endif
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
if (V_BOOL(&var2))
|
|
{
|
|
// object has been deleted - pretend it isn't set
|
|
hr = E_ADS_PROPERTY_NOT_SET;
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"Object deleted\n");
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
}
|
|
|
|
if (V_VT(&var3) != VT_BSTR) {
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"Get bad data 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
wcscpy(pwszFqdn,V_BSTR(&var3));
|
|
|
|
CleanExit:
|
|
VariantClear(&var2);
|
|
VariantClear(&var3);
|
|
|
|
if (NULL != pADs2) {
|
|
pADs2->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// First call with fUseReg TRUE; if the returned server doesn't work
|
|
// call again with fUseReg FALSE
|
|
//
|
|
|
|
extern "C"
|
|
HRESULT
|
|
FindEnterpriseServer(TLS_HANDLE *phBinding)
|
|
{
|
|
HRESULT hr;
|
|
LPWSTR *rgwszServers = NULL;
|
|
LPWSTR pwszServerNames = NULL;
|
|
DWORD entriesread, i;
|
|
|
|
if (phBinding == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
goto CleanExit;
|
|
}
|
|
|
|
*phBinding = NULL;
|
|
|
|
hr = GetLicenseServersFromReg(ENTERPRISE_SERVER_MULTI,&pwszServerNames,&entriesread,&rgwszServers);
|
|
if (FAILED(hr))
|
|
{
|
|
goto CleanExit;
|
|
}
|
|
|
|
for (i = 0; i < entriesread; i++)
|
|
{
|
|
TLS_HANDLE pContext=NULL;
|
|
RPC_STATUS rpcStatus;
|
|
DWORD dwVersion;
|
|
|
|
if(!(pContext = TLSConnectToLsServer(rgwszServers[i])))
|
|
{
|
|
break;
|
|
}
|
|
|
|
rpcStatus = TLSGetVersion(pContext,&dwVersion);
|
|
if (rpcStatus != RPC_S_OK)
|
|
{
|
|
TLSDisconnect(&pContext);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// No Beta <--> RTM server.
|
|
//
|
|
//
|
|
// TLSIsBetaNTServer() returns TRUE if eval NT
|
|
// IS_LSSERVER_RTM() returns TRUE if LS is an RTM.
|
|
//
|
|
if( TLSIsBetaNTServer() == IS_LSSERVER_RTM(dwVersion) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!(dwVersion & TLS_VERSION_ENTERPRISE_BIT))
|
|
{
|
|
TLSDisconnect(&pContext);
|
|
continue;
|
|
}
|
|
|
|
*phBinding = pContext;
|
|
break;
|
|
}
|
|
|
|
CleanExit:
|
|
if (pwszServerNames)
|
|
LocalFree(pwszServerNames);
|
|
|
|
if (rgwszServers)
|
|
LocalFree(rgwszServers);
|
|
|
|
return hr;
|
|
}
|
|
|
|
extern "C"
|
|
HRESULT
|
|
GetAllEnterpriseServers(WCHAR ***ppszServers, DWORD *pdwCount)
|
|
{
|
|
LPWSTR pwszSiteName = NULL;
|
|
IADs * pADs = NULL;
|
|
VARIANT var;
|
|
VARIANT var2;
|
|
LPWSTR pwszLicenseSettings = NULL;
|
|
HRESULT hr;
|
|
VARIANT HUGEP *pvar = NULL;
|
|
LONG lLower, lUpper;
|
|
int i;
|
|
LPWSTR pwszRegServers = NULL;
|
|
LPWSTR pwszRegServersTmp;
|
|
DWORD cchServer, cchServers;
|
|
int cServers = 0;
|
|
|
|
if (ppszServers != NULL)
|
|
*ppszServers = NULL;
|
|
|
|
// We're going to use ADSI, so initialize COM. We don't
|
|
// care about OLE 1.0 so disable OLE 1 DDE
|
|
|
|
hr = CoInitialize(NULL);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
VariantInit(&var);
|
|
VariantInit(&var2);
|
|
|
|
hr = GetLicenseSettingsObject(&var,
|
|
&pwszLicenseSettings,
|
|
&pwszSiteName,
|
|
&pADs);
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"GetLicenseSettingsObject failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr = GetAllServers(pADs,&var2);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"GetAllServers failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr = SafeArrayGetLBound( V_ARRAY(&var2), 1, &lLower );
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"SafeArrayGetLBound failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr = SafeArrayGetUBound( V_ARRAY(&var2), 1, &lUpper );
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"SafeArrayGetUBound failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
|
|
// Get a pointer to the elements of the safearray.
|
|
hr = SafeArrayAccessData(V_ARRAY(&var2), (void HUGEP* FAR*)&pvar);
|
|
|
|
if (FAILED(hr)) {
|
|
goto CleanExit;
|
|
}
|
|
|
|
if (ppszServers != NULL) {
|
|
*ppszServers = (WCHAR * *) LocalAlloc(LPTR,(lUpper-lLower+1) * sizeof(WCHAR *));
|
|
|
|
if (*ppszServers == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"LocalAlloc failed 0x%lx\n",hr);
|
|
#endif
|
|
goto CleanExit;
|
|
}
|
|
}
|
|
|
|
pwszRegServers = (LPWSTR) LocalAlloc(LPTR,2*sizeof(WCHAR));
|
|
if (NULL == pwszRegServers)
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"Out of memory\n");
|
|
#endif
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
cchServers = 2;
|
|
pwszRegServers[0] = pwszRegServers[1] = L'\0';
|
|
|
|
for (i = 0; i < lUpper-lLower+1; i++)
|
|
{
|
|
WCHAR *szServer = (WCHAR *) LocalAlloc(LPTR,MAX_PATH*2);
|
|
|
|
if (szServer == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"LocalAlloc failed 0x%lx\n",hr);
|
|
#endif
|
|
|
|
if (ppszServers != NULL) {
|
|
for (int j = 0; j < cServers; j++)
|
|
{
|
|
LocalFree((*ppszServers)[j]);
|
|
}
|
|
LocalFree(*ppszServers);
|
|
}
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
hr = DnToFqdn(V_BSTR(pvar+cServers),szServer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"DnToFqdn failed 0x%lx\n",hr);
|
|
#endif
|
|
|
|
LocalFree(szServer);
|
|
|
|
continue;
|
|
}
|
|
|
|
cchServer = wcslen(szServer);
|
|
|
|
pwszRegServersTmp = (LPWSTR) LocalReAlloc(pwszRegServers,(cchServers+cchServer+1)*sizeof(TCHAR),LHND);
|
|
if (NULL == pwszRegServersTmp)
|
|
{
|
|
#ifdef PRIVATEDEBUG
|
|
wprintf(L"LocalReAlloc failed 0x%lx\n",hr);
|
|
#endif
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
if (ppszServers != NULL) {
|
|
for (int j = 0; j < cServers; j++)
|
|
{
|
|
LocalFree((*ppszServers)[j]);
|
|
}
|
|
LocalFree(*ppszServers);
|
|
}
|
|
LocalFree(szServer);
|
|
|
|
goto CleanExit;
|
|
}
|
|
|
|
pwszRegServers = pwszRegServersTmp;
|
|
|
|
if (cchServers == 2)
|
|
{
|
|
wcscpy(pwszRegServers,szServer);
|
|
|
|
cchServers += cchServer;
|
|
} else
|
|
{
|
|
wcscpy(pwszRegServers+cchServers-1,szServer);
|
|
|
|
cchServers += cchServer + 1;
|
|
|
|
}
|
|
pwszRegServers[cchServers-1] = L'\0';
|
|
|
|
if (ppszServers != NULL)
|
|
{
|
|
(*ppszServers)[cServers] = szServer;
|
|
}
|
|
|
|
cServers++;
|
|
}
|
|
|
|
if (pdwCount != NULL)
|
|
*pdwCount = cServers;
|
|
|
|
WriteLicenseServersToReg(ENTERPRISE_SERVER_MULTI,pwszRegServers,cchServers);
|
|
|
|
CleanExit:
|
|
VariantClear(&var);
|
|
VariantClear(&var2);
|
|
|
|
if (pwszSiteName != NULL) { // Allocated from DsGetSiteName
|
|
NetApiBufferFree(pwszSiteName);
|
|
}
|
|
|
|
if (pwszLicenseSettings != NULL) {
|
|
LocalFree(pwszLicenseSettings);
|
|
}
|
|
|
|
if (pvar != NULL) {
|
|
SafeArrayUnaccessData(V_ARRAY(&var2));
|
|
}
|
|
|
|
if (NULL != pADs) {
|
|
pADs->Release();
|
|
}
|
|
|
|
if (pwszRegServers) {
|
|
LocalFree(pwszRegServers);
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
if ((ppszServers != NULL) && (FAILED(hr)))
|
|
*ppszServers = NULL;
|
|
|
|
return hr;
|
|
}
|