windows-nt/Source/XPSP1/NT/termsrv/license/tlserver/tlsapi/efind.cpp

836 lines
19 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*
** 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;
}