939 lines
23 KiB
C++
939 lines
23 KiB
C++
|
|
||
|
/*
|
||
|
* Purpose: C++ API for finding the telephony
|
||
|
* servers in Active Directory
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifndef UNICODE
|
||
|
#define UNICODE
|
||
|
#endif
|
||
|
#ifndef _UNICODE
|
||
|
#define _UNICODE
|
||
|
#endif
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <objbase.h>
|
||
|
#include <activeds.h>
|
||
|
|
||
|
#include "tspi.h"
|
||
|
#include "tapi.h"
|
||
|
#include "dslookup.h"
|
||
|
#include "utils.h"
|
||
|
|
||
|
#include "tchar.h"
|
||
|
|
||
|
const TCHAR gszNoDSQuery[] = TEXT("NoDSQuery");
|
||
|
const TCHAR gszStatusActive[] = TEXT("S{Active}");
|
||
|
const TCHAR gszTTLWithBrace[] = TEXT("TTL{");
|
||
|
|
||
|
//
|
||
|
// Utility functions
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// GetIntFromString
|
||
|
// Utility function used for retrieving TTL information
|
||
|
// Parameters:
|
||
|
// sz - String that contains the integer
|
||
|
// dwDigits - Number of digits to convert
|
||
|
//
|
||
|
int GetIntFromString (LPTSTR & sz, DWORD dwDigits)
|
||
|
{
|
||
|
int iRet = 0;
|
||
|
|
||
|
while (*sz != 0 && dwDigits)
|
||
|
{
|
||
|
iRet = ((iRet << 3) + (iRet << 1)) + // IRet * 10
|
||
|
+ (*sz - '0');
|
||
|
++sz;
|
||
|
--dwDigits;
|
||
|
}
|
||
|
|
||
|
return iRet;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Rules:
|
||
|
// The following codes are not thread safe, the caller
|
||
|
// needs to be concious about synchronization.
|
||
|
// Currently theses are only used in remotesp.tsp
|
||
|
//
|
||
|
|
||
|
/**********************************************************
|
||
|
* Get TAPI servers list from the registry
|
||
|
*********************************************************/
|
||
|
|
||
|
DWORD gdwCurServerNum = 0;
|
||
|
HKEY ghRegistry = NULL;
|
||
|
|
||
|
BOOL
|
||
|
RegOpenServerLookup(
|
||
|
HKEY hRegistry
|
||
|
)
|
||
|
{
|
||
|
if (NULL != ghRegistry)
|
||
|
{
|
||
|
// Already have a search in progress or the
|
||
|
// caller did not close the last search.
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ghRegistry = hRegistry;
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
RegGetNextServer(
|
||
|
LPTSTR pszServerName,
|
||
|
DWORD dwSize
|
||
|
)
|
||
|
{
|
||
|
DWORD dwRet;
|
||
|
LOG((TL_TRACE, "GetNextServer entered"));
|
||
|
|
||
|
TCHAR szServerN[24];
|
||
|
DWORD dwType;
|
||
|
|
||
|
wsprintf(szServerN, TEXT("Server%d"), gdwCurServerNum++);
|
||
|
|
||
|
LOG((TL_INFO, "RegGetNextServer: Getting server %d from reg", gdwCurServerNum-1));
|
||
|
|
||
|
dwRet = RegQueryValueEx(
|
||
|
ghRegistry,
|
||
|
szServerN,
|
||
|
0,
|
||
|
&dwType,
|
||
|
(LPBYTE) pszServerName,
|
||
|
&dwSize
|
||
|
);
|
||
|
if (ERROR_SUCCESS != dwRet)
|
||
|
{
|
||
|
LOG((TL_INFO, "Got last server"));
|
||
|
LOG((TL_TRACE, "GetNextServer exited"));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
LOG((TL_TRACE, "GetNextServer exited"));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
RegCloseLookup(
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
LOG((TL_INFO, "Closing directory lookup"));
|
||
|
|
||
|
ghRegistry = NULL;
|
||
|
gdwCurServerNum = 0;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**********************************************************
|
||
|
* Enumerate published telephony servers
|
||
|
*********************************************************/
|
||
|
|
||
|
typedef struct _TAPISRV_LOOKUP_CTX {
|
||
|
ADS_SEARCH_HANDLE hDirSearch;
|
||
|
IDirectorySearch * pDirSearch;
|
||
|
} TAPISRV_LOOKUP_CTX, *PTAPISRV_LOOKUP_CTX;
|
||
|
|
||
|
// gszTapisrvGuid needs to be consistant with server\dspub.cpp
|
||
|
const WCHAR gszTapisrvGuid[] = L"keywords=B1A37774-E3F7-488E-ADBFD4DB8A4AB2E5";
|
||
|
|
||
|
//
|
||
|
// GetGC
|
||
|
//
|
||
|
// Retrieve the IDirectorySearch of the Global Catalog (GC)
|
||
|
// for SCP maintenance / discovery
|
||
|
//
|
||
|
|
||
|
HRESULT GetGC (IDirectorySearch ** ppGC)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
IEnumVARIANT * pEnum = NULL;
|
||
|
IADsContainer * pCont = NULL;
|
||
|
VARIANT var;
|
||
|
IDispatch * pDisp = NULL;
|
||
|
ULONG lFetch;
|
||
|
|
||
|
// Set IDirectorySearch pointer to NULL.
|
||
|
*ppGC = NULL;
|
||
|
|
||
|
// First, bind to the GC: namespace container object. The "real" GC DN
|
||
|
// is a single immediate child of the GC: namespace, which must
|
||
|
// be obtained using enumeration.
|
||
|
hr = ADsOpenObject(
|
||
|
TEXT("GC:"),
|
||
|
NULL,
|
||
|
NULL,
|
||
|
ADS_SECURE_AUTHENTICATION, //Use Secure Authentication
|
||
|
IID_IADsContainer,
|
||
|
(void**)&pCont
|
||
|
);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((TL_ERROR, "ADsOpenObject failed: 0x%x\n", hr));
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// Fetch an enumeration interface for the GC container.
|
||
|
hr = ADsBuildEnumerator(pCont, &pEnum);
|
||
|
if (FAILED(hr)) {
|
||
|
LOG((TL_ERROR, "ADsBuildEnumerator failed: 0x%x\n", hr));
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
//Now enumerate. There's only one child of the GC: object.
|
||
|
hr = ADsEnumerateNext(pEnum, 1, &var, &lFetch);
|
||
|
if (FAILED(hr)) {
|
||
|
LOG((TL_ERROR, "ADsEnumerateNext failed: 0x%x\n", hr));
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
if (( hr == S_OK ) && ( lFetch == 1 ) )
|
||
|
{
|
||
|
pDisp = V_DISPATCH(&var);
|
||
|
hr = pDisp->QueryInterface( IID_IDirectorySearch, (void**)ppGC);
|
||
|
}
|
||
|
|
||
|
cleanup:
|
||
|
if (pEnum)
|
||
|
{
|
||
|
ADsFreeEnumerator(pEnum);
|
||
|
}
|
||
|
if (pCont)
|
||
|
{
|
||
|
pCont->Release();
|
||
|
}
|
||
|
if (pDisp)
|
||
|
{
|
||
|
(pDisp)->Release();
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// DsOpenServerLookup
|
||
|
// Start the operation of tapisrv server lookup
|
||
|
// pctx - The lookup context
|
||
|
//
|
||
|
|
||
|
HRESULT
|
||
|
DsOpenServerLookup(
|
||
|
PTAPISRV_LOOKUP_CTX pctx
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
ADS_SEARCHPREF_INFO SearchPref[3];
|
||
|
BOOL bInited = FALSE;
|
||
|
DWORD dwPref;
|
||
|
|
||
|
WCHAR *szAttribs[]={
|
||
|
L"distinguishedName"
|
||
|
};
|
||
|
|
||
|
if (pctx == NULL)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
|
||
|
pctx->hDirSearch = NULL;
|
||
|
pctx->pDirSearch = NULL;
|
||
|
|
||
|
hr = CoInitializeEx (NULL, COINIT_MULTITHREADED);
|
||
|
if (FAILED (hr))
|
||
|
{
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
bInited = TRUE;
|
||
|
|
||
|
// Get the global catalog
|
||
|
hr = GetGC (&pctx->pDirSearch);
|
||
|
if (FAILED (hr) || pctx->pDirSearch == NULL)
|
||
|
{
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
|
||
|
// Set up the search. We want to do a deep search.
|
||
|
// Note that we are not expecting thousands of objects
|
||
|
// in this example, so we will ask for 10 rows / page.
|
||
|
dwPref=sizeof(SearchPref)/sizeof(ADS_SEARCHPREF_INFO);
|
||
|
SearchPref[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
|
||
|
SearchPref[0].vValue.dwType = ADSTYPE_INTEGER;
|
||
|
SearchPref[0].vValue.Integer = ADS_SCOPE_SUBTREE;
|
||
|
|
||
|
SearchPref[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
|
||
|
SearchPref[1].vValue.dwType = ADSTYPE_INTEGER;
|
||
|
SearchPref[1].vValue.Integer = 10;
|
||
|
|
||
|
SearchPref[2].dwSearchPref = ADS_SEARCHPREF_TIME_LIMIT;
|
||
|
SearchPref[2].vValue.dwType = ADSTYPE_INTEGER;
|
||
|
SearchPref[2].vValue.Integer = 5 * 60; // 5 minute search timeout
|
||
|
|
||
|
hr = pctx->pDirSearch->SetSearchPreference(SearchPref, dwPref);
|
||
|
if (FAILED(hr)) {
|
||
|
LOG((TL_ERROR, "Failed to set search prefs: hr:0x%x\n", hr));
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
|
||
|
// Now execute the search
|
||
|
hr = pctx->pDirSearch->ExecuteSearch(
|
||
|
(LPWSTR)gszTapisrvGuid,
|
||
|
szAttribs,
|
||
|
sizeof(szAttribs) / sizeof(WCHAR *),
|
||
|
&pctx->hDirSearch
|
||
|
);
|
||
|
|
||
|
ExitHere:
|
||
|
if (FAILED(hr) && pctx != NULL)
|
||
|
{
|
||
|
if (pctx->pDirSearch)
|
||
|
{
|
||
|
pctx->pDirSearch->Release();
|
||
|
}
|
||
|
}
|
||
|
if (FAILED(hr) && bInited)
|
||
|
{
|
||
|
CoUninitialize ();
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// DsGetNextServer
|
||
|
//
|
||
|
// Return the next server name (in ANSI since that is what the
|
||
|
// RPC subsystem uses)
|
||
|
//
|
||
|
// returns S_FALSE if no more server to enumerate
|
||
|
//
|
||
|
|
||
|
HRESULT
|
||
|
DsGetNextServer(
|
||
|
PTAPISRV_LOOKUP_CTX pctx,
|
||
|
LPTSTR pszServerName,
|
||
|
DWORD dwSize
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
ADS_SEARCH_COLUMN Col;
|
||
|
TCHAR szDN[MAX_PATH];
|
||
|
WCHAR *szAttribs[]={
|
||
|
L"serviceDNSName",
|
||
|
L"serviceBindingInformation",
|
||
|
};
|
||
|
ADS_ATTR_INFO *pPropEntries = NULL;
|
||
|
DWORD dwNumAttrGot;
|
||
|
IDirectoryObject * pSCP = NULL;
|
||
|
int i;
|
||
|
LPWSTR wsz;
|
||
|
BOOL bCheckedBinding;
|
||
|
|
||
|
if (pctx == NULL || pctx->pDirSearch == NULL ||
|
||
|
pctx->hDirSearch == NULL ||
|
||
|
dwSize < sizeof(WCHAR))
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
|
||
|
hr = pctx->pDirSearch->GetNextRow(pctx->hDirSearch);
|
||
|
if (SUCCEEDED (hr) && hr != S_ADS_NOMORE_ROWS)
|
||
|
{
|
||
|
hr = pctx->pDirSearch->GetColumn(
|
||
|
pctx->hDirSearch,
|
||
|
L"distinguishedName",
|
||
|
&Col
|
||
|
);
|
||
|
if (FAILED (hr))
|
||
|
{
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
_tcscpy (szDN, TEXT("LDAP://"));
|
||
|
_tcsncpy (
|
||
|
szDN + _tcslen (szDN),
|
||
|
Col.pADsValues->CaseExactString,
|
||
|
sizeof(szDN)/sizeof(TCHAR) - _tcslen (szDN)
|
||
|
);
|
||
|
pctx->pDirSearch->FreeColumn(&Col);
|
||
|
hr = ADsGetObject (
|
||
|
szDN,
|
||
|
IID_IDirectoryObject,
|
||
|
(void **)&pSCP
|
||
|
);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
LOG((TL_ERROR, "DsGetNextServer: ADsGetObject %S failed", szDN));
|
||
|
hr = S_FALSE; // return a non-critical error so that we
|
||
|
// ignore this server but don't abandon the search
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
LOG((TL_TRACE, "DsGetNextServer: ADsGetObject %S succeeded", szDN));
|
||
|
hr = pSCP->GetObjectAttributes (
|
||
|
szAttribs,
|
||
|
sizeof(szAttribs) / sizeof(WCHAR *),
|
||
|
&pPropEntries,
|
||
|
&dwNumAttrGot
|
||
|
);
|
||
|
if (FAILED(hr) || dwNumAttrGot != sizeof(szAttribs) / sizeof(WCHAR *))
|
||
|
{
|
||
|
LOG((TL_ERROR, "DsGetNextServer: GetObjectAttributes %S failed", szDN));
|
||
|
hr = S_FALSE;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
LOG((TL_TRACE, "DsGetNextServer: GetObjectAttributes %S succeeded", szDN));
|
||
|
|
||
|
bCheckedBinding = FALSE;
|
||
|
for (i=0;i<(int)dwNumAttrGot;i++)
|
||
|
{
|
||
|
if (_tcsicmp(TEXT("serviceDNSName"), pPropEntries[i].pszAttrName) ==0 &&
|
||
|
(pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_EXACT_STRING ||
|
||
|
pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_IGNORE_STRING))
|
||
|
{
|
||
|
_tcsncpy (
|
||
|
pszServerName,
|
||
|
pPropEntries[i].pADsValues->CaseExactString,
|
||
|
dwSize/sizeof(TCHAR)
|
||
|
);
|
||
|
pszServerName[dwSize/sizeof(TCHAR) - 1] = '\0';
|
||
|
if (bCheckedBinding)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (_tcsicmp(TEXT("serviceBindingInformation"), pPropEntries[i].pszAttrName) ==0 &&
|
||
|
(pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_EXACT_STRING ||
|
||
|
pPropEntries[i].pADsValues->dwType == ADSTYPE_CASE_IGNORE_STRING))
|
||
|
{
|
||
|
SYSTEMTIME st;
|
||
|
FILETIME ft1, ft2;
|
||
|
|
||
|
bCheckedBinding = TRUE;
|
||
|
wsz = pPropEntries[i].pADsValues->CaseExactString;
|
||
|
wsz = wcsstr (wsz, gszStatusActive);
|
||
|
if (wsz == NULL)
|
||
|
{
|
||
|
// No server status information or server is not active
|
||
|
// ignore this server
|
||
|
LOG((TL_ERROR, "DsGetNextServer: %S No server status information", szDN));
|
||
|
hr = S_FALSE;
|
||
|
break;
|
||
|
}
|
||
|
wsz += _tcslen(gszStatusActive); // skip "S{Active}" itself
|
||
|
wsz = wcsstr (wsz, gszTTLWithBrace);
|
||
|
if (wsz == NULL)
|
||
|
{
|
||
|
// No TTL found, corrupt serviceBindingInformation, ignore
|
||
|
LOG((TL_ERROR, "DsGetNextServer: %S No TTL found", szDN));
|
||
|
hr = S_FALSE;
|
||
|
break;
|
||
|
}
|
||
|
wsz += _tcslen (gszTTLWithBrace); // skip "TTL{"
|
||
|
|
||
|
//
|
||
|
// The following codes parses the TTL information
|
||
|
// created in server\dspub.cpp. They need to be
|
||
|
// consistant. The current format is 5 digits for
|
||
|
// year & 3 digits for milliseconds, 2 digits for
|
||
|
// the remaining
|
||
|
//
|
||
|
st.wYear = (WORD) GetIntFromString (wsz, 5);
|
||
|
st.wMonth = (WORD) GetIntFromString (wsz, 2);
|
||
|
st.wDay = (WORD) GetIntFromString (wsz, 2),
|
||
|
st.wHour = (WORD) GetIntFromString (wsz, 2);
|
||
|
st.wMinute = (WORD) GetIntFromString (wsz, 2);
|
||
|
st.wSecond = (WORD) GetIntFromString (wsz, 2);
|
||
|
st.wMilliseconds = (WORD) GetIntFromString (wsz, 3);
|
||
|
SystemTimeToFileTime (&st, &ft1);
|
||
|
GetSystemTimeAsFileTime (&ft2);
|
||
|
if (CompareFileTime (&ft1, &ft2) < 0)
|
||
|
{
|
||
|
// The TapiSCP object has passed its TTL, ignore
|
||
|
hr = S_FALSE;
|
||
|
LOG((TL_ERROR, "DsGetNextServer: %S The TapiSCP object has passed its TTL", szDN));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (i == (int) dwNumAttrGot)
|
||
|
{
|
||
|
// Did not find an attribute
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExitHere:
|
||
|
if (pSCP)
|
||
|
pSCP->Release();
|
||
|
|
||
|
if (pPropEntries)
|
||
|
FreeADsMem(pPropEntries);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// DsCloseLookup
|
||
|
// Close the TAPI DS published server lookup identified by pctx
|
||
|
//
|
||
|
|
||
|
HRESULT
|
||
|
DsCloseLookup(
|
||
|
PTAPISRV_LOOKUP_CTX pctx
|
||
|
)
|
||
|
{
|
||
|
if (pctx && pctx->pDirSearch && pctx->hDirSearch)
|
||
|
{
|
||
|
pctx->pDirSearch->CloseSearchHandle(pctx->hDirSearch);
|
||
|
}
|
||
|
if (pctx && pctx->pDirSearch)
|
||
|
{
|
||
|
pctx->pDirSearch->Release();
|
||
|
}
|
||
|
CoUninitialize ();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/**********************************************************
|
||
|
* Get TAPI servers list remotesp.tsp should contact
|
||
|
* Servers include those specified in registry through
|
||
|
* tcmsetup.exe and those servers published in the DS
|
||
|
*********************************************************/
|
||
|
|
||
|
typedef struct _SERVER_LOOKUP_ENTRY {
|
||
|
TCHAR szServer[MAX_PATH];
|
||
|
BOOL bFromReg;
|
||
|
} SERVER_LOOKUP_ENTRY, *PSERVER_LOOKUP_ENTRY;
|
||
|
|
||
|
typedef struct _SERVER_LOOKUP {
|
||
|
DWORD dwTotalEntries;
|
||
|
DWORD dwUsedEntries;
|
||
|
SERVER_LOOKUP_ENTRY * aEntries;
|
||
|
} SERVER_LOOKUP, *PSERVER_LOOKUP;
|
||
|
|
||
|
SERVER_LOOKUP gLookup;
|
||
|
DWORD gdwCurIndex;
|
||
|
|
||
|
//
|
||
|
// AddEntry : return FALSE if failed; otherwise, return true
|
||
|
//
|
||
|
|
||
|
BOOL
|
||
|
AddEntry (
|
||
|
LPTSTR szServer,
|
||
|
BOOL bFromReg
|
||
|
)
|
||
|
{
|
||
|
LPTSTR psz;
|
||
|
|
||
|
if (gLookup.dwUsedEntries >= gLookup.dwTotalEntries)
|
||
|
{
|
||
|
PSERVER_LOOKUP_ENTRY pNew;
|
||
|
|
||
|
pNew = (PSERVER_LOOKUP_ENTRY) DrvAlloc (
|
||
|
sizeof(SERVER_LOOKUP_ENTRY) * (gLookup.dwTotalEntries + 5)
|
||
|
);
|
||
|
if (pNew == NULL)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (gLookup.dwUsedEntries > 0)
|
||
|
{
|
||
|
CopyMemory (
|
||
|
pNew,
|
||
|
gLookup.aEntries,
|
||
|
sizeof(SERVER_LOOKUP_ENTRY) * gLookup.dwTotalEntries
|
||
|
);
|
||
|
}
|
||
|
if (gLookup.aEntries)
|
||
|
{
|
||
|
DrvFree (gLookup.aEntries);
|
||
|
}
|
||
|
gLookup.aEntries = pNew;
|
||
|
gLookup.dwTotalEntries += 5;
|
||
|
}
|
||
|
wcsncpy (
|
||
|
gLookup.aEntries[gLookup.dwUsedEntries].szServer,
|
||
|
szServer,
|
||
|
sizeof(gLookup.aEntries[gLookup.dwUsedEntries].szServer)/sizeof(TCHAR)
|
||
|
);
|
||
|
psz = _tcschr(gLookup.aEntries[gLookup.dwUsedEntries].szServer, TEXT('.'));
|
||
|
if (psz != NULL)
|
||
|
{
|
||
|
*psz = 0;
|
||
|
}
|
||
|
gLookup.aEntries[gLookup.dwUsedEntries].bFromReg = bFromReg;
|
||
|
++gLookup.dwUsedEntries;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
IsServerInListOrSelf (
|
||
|
LPTSTR szServer
|
||
|
)
|
||
|
{
|
||
|
int i;
|
||
|
TCHAR szServer1[MAX_PATH + 1];
|
||
|
LPTSTR psz;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
_tcsncpy (szServer1, szServer, MAX_PATH);
|
||
|
szServer1[MAX_PATH] = 0;
|
||
|
|
||
|
// A computer name might be DNS name like comp1.microsoft.com
|
||
|
// only compare the computer name
|
||
|
psz = _tcschr(szServer1, TEXT('.'));
|
||
|
if (psz != NULL)
|
||
|
{
|
||
|
*psz = 0;
|
||
|
}
|
||
|
for (i = 0; i < (int)gLookup.dwUsedEntries; ++i)
|
||
|
{
|
||
|
if (_tcsicmp (szServer1, gLookup.aEntries[i].szServer) == 0)
|
||
|
{
|
||
|
bRet = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!bRet)
|
||
|
{
|
||
|
TCHAR szSelf[MAX_PATH];
|
||
|
DWORD dwSize = sizeof(szSelf);
|
||
|
|
||
|
if (GetComputerName (szSelf, &dwSize))
|
||
|
{
|
||
|
if (_tcsicmp (szServer1, szSelf) == 0)
|
||
|
{
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL OpenServerLookup (
|
||
|
HKEY hRegistry
|
||
|
)
|
||
|
{
|
||
|
BOOL bRet = TRUE;
|
||
|
TCHAR szServer[MAX_PATH];
|
||
|
TAPISRV_LOOKUP_CTX ctx;
|
||
|
HRESULT hr;
|
||
|
DWORD dwNoDSQuery = 0;
|
||
|
DWORD dwSize = sizeof(dwNoDSQuery);
|
||
|
|
||
|
gLookup.dwTotalEntries = 0;
|
||
|
gLookup.dwUsedEntries = 0;
|
||
|
gLookup.aEntries = NULL;
|
||
|
|
||
|
//
|
||
|
// First add the computer from registry
|
||
|
//
|
||
|
if (RegOpenServerLookup (hRegistry))
|
||
|
{
|
||
|
while (RegGetNextServer (szServer, sizeof(szServer)))
|
||
|
{
|
||
|
if (!IsServerInListOrSelf (szServer))
|
||
|
{
|
||
|
AddEntry (szServer, TRUE);
|
||
|
}
|
||
|
}
|
||
|
RegCloseLookup ();
|
||
|
}
|
||
|
|
||
|
if (hRegistry != NULL)
|
||
|
{
|
||
|
if (ERROR_SUCCESS != RegQueryValueEx (
|
||
|
hRegistry,
|
||
|
gszNoDSQuery,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
(LPBYTE)&dwNoDSQuery,
|
||
|
&dwSize
|
||
|
))
|
||
|
{
|
||
|
dwNoDSQuery = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Next add the computer from DS unless disabled
|
||
|
//
|
||
|
if (dwNoDSQuery == 0)
|
||
|
{
|
||
|
if (DsOpenServerLookup (&ctx) == S_OK)
|
||
|
{
|
||
|
while (SUCCEEDED(hr = DsGetNextServer (&ctx,szServer, sizeof(szServer))))
|
||
|
{
|
||
|
if (hr == S_ADS_NOMORE_ROWS)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
else if (hr != S_OK)
|
||
|
{
|
||
|
continue; // Server needs to be ignored
|
||
|
}
|
||
|
if (szServer[0] != 0 && !IsServerInListOrSelf (szServer))
|
||
|
{
|
||
|
AddEntry (szServer, FALSE);
|
||
|
}
|
||
|
}
|
||
|
DsCloseLookup (&ctx);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gdwCurIndex = 0;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL GetNextServer (
|
||
|
LPSTR szServer,
|
||
|
DWORD dwSize,
|
||
|
BOOL * pbReg
|
||
|
)
|
||
|
{
|
||
|
BOOL bRet = TRUE;
|
||
|
DWORD dwRet;
|
||
|
|
||
|
if (gdwCurIndex >= gLookup.dwUsedEntries)
|
||
|
{
|
||
|
bRet = FALSE;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
if (pbReg != NULL)
|
||
|
{
|
||
|
*pbReg = gLookup.aEntries[gdwCurIndex].bFromReg;
|
||
|
}
|
||
|
dwRet = WideCharToMultiByte(
|
||
|
GetACP(),
|
||
|
0,
|
||
|
gLookup.aEntries[gdwCurIndex].szServer,
|
||
|
-1,
|
||
|
szServer,
|
||
|
dwSize,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
if (dwRet == 0)
|
||
|
{
|
||
|
bRet = FALSE;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
++gdwCurIndex;
|
||
|
|
||
|
ExitHere:
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL CloseLookup (
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
if (gLookup.aEntries)
|
||
|
{
|
||
|
DrvFree (gLookup.aEntries);
|
||
|
}
|
||
|
gLookup.aEntries = NULL;
|
||
|
gLookup.dwTotalEntries = 0;
|
||
|
gLookup.dwUsedEntries = 0;
|
||
|
gdwCurIndex = 0;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
HRESULT SockStartup (
|
||
|
RSPSOCKET * pSocket
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
BOOL bCleanup = FALSE;
|
||
|
WSADATA wsadata;
|
||
|
WORD wVersionRequested = MAKEWORD( 2, 2 );
|
||
|
|
||
|
if (pSocket == NULL)
|
||
|
{
|
||
|
hr = LINEERR_INVALPARAM;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
ZeroMemory (pSocket, sizeof(RSPSOCKET));
|
||
|
bCleanup = TRUE;
|
||
|
|
||
|
ZeroMemory (pSocket, sizeof(RSPSOCKET));
|
||
|
|
||
|
pSocket->hWS2 = LoadLibrary (TEXT("ws2_32.dll"));
|
||
|
if (pSocket->hWS2 == NULL)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
|
||
|
pSocket->pFnWSAStartup = (PFNWSASTARTUP)GetProcAddress (
|
||
|
pSocket->hWS2,
|
||
|
"WSAStartup"
|
||
|
);
|
||
|
pSocket->pFnWSACleanup = (PFNWSACLEANUP)GetProcAddress (
|
||
|
pSocket->hWS2,
|
||
|
"WSACleanup"
|
||
|
);
|
||
|
pSocket->pFngethostbyname = (PFNGETHOSTBYNAME)GetProcAddress(
|
||
|
pSocket->hWS2,
|
||
|
"gethostbyname"
|
||
|
);
|
||
|
if (pSocket->pFnWSAStartup == NULL ||
|
||
|
pSocket->pFnWSACleanup == NULL ||
|
||
|
pSocket->pFngethostbyname == NULL)
|
||
|
{
|
||
|
hr = LINEERR_OPERATIONFAILED;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
|
||
|
pSocket->hICMP = LoadLibrary (TEXT("icmp.dll"));
|
||
|
if (pSocket->hICMP == NULL)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
pSocket->pFnIcmpCreateFile = (PFNICMPCREATEFILE)GetProcAddress (
|
||
|
pSocket->hICMP,
|
||
|
"IcmpCreateFile"
|
||
|
);
|
||
|
pSocket->pFnIcmpCloseHandle = (PFNICMPCLOSEHANDLE)GetProcAddress (
|
||
|
pSocket->hICMP,
|
||
|
"IcmpCloseHandle"
|
||
|
);
|
||
|
pSocket->pFnIcmpSendEcho = (PFNICMPSENDECHO)GetProcAddress (
|
||
|
pSocket->hICMP,
|
||
|
"IcmpSendEcho"
|
||
|
);
|
||
|
if (pSocket->pFnIcmpCreateFile == NULL ||
|
||
|
pSocket->pFnIcmpCloseHandle == NULL ||
|
||
|
pSocket->pFnIcmpSendEcho == NULL)
|
||
|
{
|
||
|
hr = LINEERR_OPERATIONFAILED;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
|
||
|
hr = (*pSocket->pFnWSAStartup)(
|
||
|
wVersionRequested,
|
||
|
&wsadata
|
||
|
);
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
|
||
|
pSocket->IcmpHandle = (*pSocket->pFnIcmpCreateFile)();
|
||
|
if (pSocket->IcmpHandle == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
(*pSocket->pFnWSACleanup)();
|
||
|
hr = LINEERR_OPERATIONFAILED;
|
||
|
}
|
||
|
|
||
|
ExitHere:
|
||
|
if (hr != S_OK && bCleanup)
|
||
|
{
|
||
|
if (pSocket->hWS2 != NULL)
|
||
|
{
|
||
|
FreeLibrary (pSocket->hWS2);
|
||
|
}
|
||
|
if (pSocket->hICMP != NULL)
|
||
|
{
|
||
|
FreeLibrary (pSocket->hICMP);
|
||
|
}
|
||
|
ZeroMemory (pSocket, sizeof(RSPSOCKET));
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
#define MAX_PACKET_SIZE 256
|
||
|
#define PING_TIMEOUT 1000
|
||
|
|
||
|
HRESULT SockIsServerResponding (
|
||
|
RSPSOCKET * pSocket,
|
||
|
char * szServer
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
unsigned long inetAddr;
|
||
|
HOSTENT * pHost;
|
||
|
BOOL bRet;
|
||
|
CHAR ReplyBuf[MAX_PACKET_SIZE];
|
||
|
|
||
|
// Validate parameters
|
||
|
if (pSocket == NULL ||
|
||
|
pSocket->hWS2 == NULL ||
|
||
|
pSocket->hICMP == NULL ||
|
||
|
pSocket->IcmpHandle == NULL ||
|
||
|
pSocket->IcmpHandle == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
hr = LINEERR_INVALPARAM;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
|
||
|
// Get the server IP address
|
||
|
pHost = (*pSocket->pFngethostbyname)(szServer);
|
||
|
if (pHost == NULL)
|
||
|
{
|
||
|
hr = LINEERR_OPERATIONFAILED;
|
||
|
goto ExitHere;
|
||
|
}
|
||
|
inetAddr = *(unsigned long *)pHost->h_addr;
|
||
|
|
||
|
// Ping the server
|
||
|
bRet = (*pSocket->pFnIcmpSendEcho)(
|
||
|
pSocket->IcmpHandle,
|
||
|
inetAddr,
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
(LPVOID)ReplyBuf,
|
||
|
sizeof(ReplyBuf),
|
||
|
PING_TIMEOUT
|
||
|
);
|
||
|
if (!bRet || ((PICMP_ECHO_REPLY)ReplyBuf)->Address != inetAddr)
|
||
|
{
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
|
||
|
ExitHere:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT SockShutdown (
|
||
|
RSPSOCKET * pSocket
|
||
|
)
|
||
|
{
|
||
|
if (pSocket != NULL)
|
||
|
{
|
||
|
if (pSocket->IcmpHandle != INVALID_HANDLE_VALUE &&
|
||
|
pSocket->IcmpHandle != NULL)
|
||
|
{
|
||
|
(*pSocket->pFnIcmpCloseHandle)(pSocket->IcmpHandle);
|
||
|
}
|
||
|
if (pSocket->hICMP != NULL)
|
||
|
{
|
||
|
FreeLibrary (pSocket->hICMP);
|
||
|
}
|
||
|
if (pSocket->hWS2 != NULL)
|
||
|
{
|
||
|
(*pSocket->pFnWSACleanup)();
|
||
|
FreeLibrary (pSocket->hWS2);
|
||
|
}
|
||
|
ZeroMemory (pSocket, sizeof(RSPSOCKET));
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|