//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996-1998 // // File: tlsapi.cpp // // Contents: // // History: 12-09-97 HueiWang Created // //--------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // // Only include RNG functions from tssec // #define NO_INCLUDE_LICENSING 1 #include #include "lscommon.h" #include "tlsrpc.h" #include "tlsapi.h" #include "tlsapip.h" #include "secstore.h" #include "lscsp.h" #include "license.h" extern "C" DWORD WINAPI TLSConnect( handle_t binding, TLS_HANDLE *pphContext ); extern "C" DWORD WINAPI TLSDisconnect( TLS_HANDLE* pphContext ); extern "C" BOOL IsSystemService(); #include // Netxxx API includes #include #include #include #define DISCOVERY_INTERVAL (60 * 60 * 1000) static HANDLE g_hCachingThreadExit = NULL; static HANDLE g_hImmediateDiscovery = NULL; static HANDLE g_hDiscoverySoon = NULL; static BOOL g_fOffSiteLicenseServer = FALSE; static PSEC_WINNT_AUTH_IDENTITY g_pRpcIdentity = NULL; #define REG_DOMAIN_SERVER_MULTI L"DomainLicenseServerMulti" #define TERMINAL_SERVICE_PARAM_DISCOVERY "SYSTEM\\CurrentControlSet\\Services\\TermService\\Parameters\\LicenseServers" // 2 second timeout #define SERVER_NP_TIMEOUT (2 * 1000) #define INSTALL_CERT_DELAY (5 * 1000) BOOL g_fInDomain = -1; LONG lLibUsage = 0; typedef struct { TLS_HANDLE *hBinding; DWORD dwTimeout; // In milliseconds - INFINITE for none LARGE_INTEGER timeInitial; // As returned by QueryPerformanceCounter } LS_ENUM_PARAM, *PLS_ENUM_PARAM; void * MIDL_user_allocate(size_t size) { return(HeapAlloc(GetProcessHeap(), 0, size)); } void MIDL_user_free( void *pointer) { HeapFree(GetProcessHeap(), 0, pointer); } #ifdef PRIVATEDEBUG // // FUNCTIONS: StartTime() // EndTime() // // USAGE: // StartTime(); // // Do some work. // mseconds = EndTime(); // // RETURN VALUE: // Milliseconds between StartTime() and EndTime() calls. LARGE_INTEGER TimeT; void StartTimeT(void) { QueryPerformanceCounter(&TimeT); } ULONG EndTimeT() { LARGE_INTEGER liDiff; LARGE_INTEGER liFreq; QueryPerformanceCounter(&liDiff); liDiff.QuadPart -= TimeT.QuadPart; liDiff.QuadPart *= 1000; // Adjust to milliseconds, shouldn't overflow... (void)QueryPerformanceFrequency(&liFreq); return ((ULONG)(liDiff.QuadPart / liFreq.QuadPart)); } #endif //+------------------------------------------------------------------------ // Function: ConnectToLsServer() // // Description: // // Binding to sepecific hydra license server // // Arguments: // // szLsServer - Hydra License Server name // // Return Value: // // RPC binding handle or NULL if error, use GetLastError() to retrieve // error. //------------------------------------------------------------------------- static TLS_HANDLE WINAPI ConnectLsServer( LPTSTR szLsServer, LPTSTR szProtocol, LPTSTR szEndPoint, DWORD dwAuthLevel ) { LPTSTR szBindingString; RPC_BINDING_HANDLE hBinding=NULL; RPC_STATUS status; TLS_HANDLE pContext=NULL; BOOL fSuccess; HKEY hKey = NULL; DWORD dwType; DWORD cbData; DWORD dwErr; DWORD dwNumRetries = 1; // default to one retry LPWSTR pszServerPrincipalName = NULL; #ifdef PRIVATEDEBUG if (NULL != szLsServer) wprintf(L"server=%s\n",szLsServer); #endif // // If this isn't local // if ((NULL != szLsServer) && (NULL != szEndPoint)) { TCHAR szPipeName[MAX_PATH+1]; if (lstrlen(szLsServer) > ((sizeof(szPipeName) / sizeof(TCHAR)) - 26)) { #ifdef PRIVATEDEBUG wprintf(L"Server name too long\n"); #endif return NULL; } // // First check if license server named pipe exists // wsprintf(szPipeName,TEXT("\\\\%s\\pipe\\%s"),szLsServer,TEXT(SZSERVICENAME)); #ifdef PRIVATEDEBUG StartTimeT(); #endif fSuccess = WaitNamedPipe(szPipeName,SERVER_NP_TIMEOUT); #ifdef PRIVATEDEBUG ULONG ulTime = EndTimeT(); wprintf(L"WaitNamedPipe time == %lu\n",ulTime); #endif if (!fSuccess) { #ifdef PRIVATEDEBUG wprintf(L"WaitNamedPipe (%s) failed 0x%x\n",szPipeName,GetLastError()); #endif return NULL; } } #ifdef PRIVATEDEBUG else wprintf(L"Not trying WaitNamedPipe\n"); #endif dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(LSERVER_DISCOVERY_PARAMETER_KEY), 0, KEY_READ, &hKey); if (dwErr == ERROR_SUCCESS) { cbData = sizeof(dwNumRetries); dwErr = RegQueryValueEx(hKey, L"NumRetries", NULL, &dwType, (PBYTE)&dwNumRetries, &cbData); RegCloseKey(hKey); } status = RpcStringBindingCompose(0, szProtocol, szLsServer, szEndPoint, 0, &szBindingString); if(status!=RPC_S_OK) { #ifdef PRIVATEDEBUG wprintf(L"RpcStringBindingCompose failed 0x%x\n",status); #endif return NULL; } status=RpcBindingFromStringBinding( szBindingString, &hBinding); RpcStringFree( &szBindingString ); if(status != RPC_S_OK) { #ifdef PRIVATEDEBUG wprintf(L"RpcBindingFromStringBinding failed 0x%x\n",status); #endif return NULL; } status = RpcMgmtSetComTimeout(hBinding,RPC_C_BINDING_MIN_TIMEOUT); if (status != RPC_S_OK) { #ifdef PRIVATEDEBUG wprintf(L"RpcMgmtSetComTimeout failed 0x%x\n",status); #endif return NULL; } BOOL fRetry = TRUE; // // Find the principle name // status = RpcMgmtInqServerPrincName(hBinding, RPC_C_AUTHN_GSS_NEGOTIATE, &pszServerPrincipalName); if(status == RPC_S_OK) { status=RpcBindingSetAuthInfo(hBinding, pszServerPrincipalName, dwAuthLevel, RPC_C_AUTHN_GSS_NEGOTIATE, g_pRpcIdentity, 0); RpcStringFree(&pszServerPrincipalName); } else goto Label; if(status == RPC_S_OK) { retry: // Obtain context handle from server status = TLSConnect( hBinding, &pContext ); if(status != ERROR_SUCCESS) { pContext = NULL; if( status == RPC_S_UNKNOWN_AUTHN_SERVICE || status == ERROR_ACCESS_DENIED && fRetry) { Label: fRetry = FALSE; //Try again with no security set status = RpcBindingSetAuthInfo(hBinding, 0, dwAuthLevel, RPC_C_AUTHN_WINNT, g_pRpcIdentity, 0); if(status == RPC_S_OK) { // Obtain context handle from server status = TLSConnect( hBinding, &pContext ); } } if((status == RPC_S_CALL_FAILED) || (status == RPC_S_CALL_FAILED_DNE)) { // // Workaround for an RPC problem where the first RPC after // the LS starts, fails // if (dwNumRetries > 0) { dwNumRetries--; goto retry; } } } } // // Memory leak // if(hBinding != NULL) { RpcBindingFree(&hBinding); } SetLastError((status == RPC_S_OK) ? ERROR_SUCCESS : status); return pContext; } //+------------------------------------------------------------------------ // Function: BindAnyServer() // // Description: // // Call back routine for TLSConnectToAnyLsServer() // // Arguments: // // See EnumerateTlsServer() // // Return Value: // // Always TRUE to terminate server enumeration //------------------------------------------------------------------------- static BOOL BindAnyServer( TLS_HANDLE hRpcBinding, LPCTSTR pszServerName, HANDLE dwUserData ) /*++ ++*/ { PLS_ENUM_PARAM pParam = (PLS_ENUM_PARAM) dwUserData; TLS_HANDLE* hBinding = pParam->hBinding; RPC_STATUS rpcStatus; HKEY hKey = NULL; DWORD dwBuffer = 0; DWORD cbBuffer = sizeof (DWORD); DWORD dwErrCode = 0; // Skip Windows 2000 License servers if (hRpcBinding != NULL) { DWORD dwSupportFlags = 0; dwErrCode = TLSGetSupportFlags( hRpcBinding, &dwSupportFlags ); if ((dwErrCode == RPC_S_OK) && !(dwSupportFlags & SUPPORT_WHISTLER_CAL)) { return FALSE; } // If the call fails => Windows 2000 LS else if(dwErrCode != RPC_S_OK) { return FALSE; } *hBinding=hRpcBinding; return TRUE; } if (pParam->dwTimeout != INFINITE) { LARGE_INTEGER timeDiff; LARGE_INTEGER timeFreq; *hBinding=hRpcBinding; QueryPerformanceCounter(&timeDiff); timeDiff.QuadPart -= pParam->timeInitial.QuadPart; timeDiff.QuadPart *= 1000; // Adjust to milliseconds, shouldn't overflow (void)QueryPerformanceFrequency(&timeFreq); if (((ULONG)(timeDiff.QuadPart / timeFreq.QuadPart)) > pParam->dwTimeout) { #ifdef PRIVATEDEBUG wprintf(L"BindAnyServer timed out\n"); #endif return TRUE; } } return FALSE; } void RandomizeArray(LPWSTR *rgwszServers, DWORD cServers) { DWORD i; LPWSTR wszServerTmp; int val; if (cServers < 2) return; srand(GetTickCount()); for (i = 0; i < cServers; i++) { val = rand() % (cServers - i); if (val == 0) continue; // // Swap # i with # (val+i) // wszServerTmp = rgwszServers[i]; rgwszServers[i] = rgwszServers[val+i]; rgwszServers[val+i] = wszServerTmp; } } HRESULT GetLicenseServersFromReg(LPWSTR wszRegKey, LPWSTR *ppwszServerNames,DWORD *pcServers, LPWSTR **prgwszServers) { HRESULT hr = S_OK; HKEY hKey = NULL; DWORD dwType; DWORD cbData = 0; LPWSTR szServers=NULL, pchServer; DWORD dwErr; DWORD i,val; DWORD iLocalComputer = (DWORD)(-1); WCHAR szLocalComputerName[MAXCOMPUTERNAMELENGTH+1] = L""; DWORD cbLocalComputerName=MAXCOMPUTERNAMELENGTH+1; *ppwszServerNames = NULL; *prgwszServers = NULL; dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(LSERVER_DISCOVERY_PARAMETER_KEY), 0, KEY_READ, &hKey); if (dwErr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(dwErr); goto CleanErr; } dwErr = RegQueryValueEx(hKey, wszRegKey, NULL, &dwType, NULL, &cbData); if (dwErr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(dwErr); goto CleanErr; } if ((dwType != REG_MULTI_SZ) || (cbData < (2 * sizeof(WCHAR)))) { hr = E_FAIL; goto CleanErr; } szServers = (LPWSTR) LocalAlloc(LPTR,cbData); if (NULL == szServers) { hr = E_OUTOFMEMORY; goto CleanErr; } dwErr = RegQueryValueEx(hKey, wszRegKey, NULL, &dwType, (PBYTE)szServers, &cbData); if (dwErr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(dwErr); goto CleanErr; } for (i = 0, pchServer = szServers; (pchServer != NULL) && (*pchServer != L'\0'); pchServer = wcschr(pchServer,L'\0')+1, i++) ; if (i == 0) { hr = E_FAIL; goto CleanErr; } *pcServers = i; *prgwszServers = (LPWSTR *)LocalAlloc(LPTR,sizeof(LPWSTR) * (*pcServers)); if (*prgwszServers == NULL) { hr = E_OUTOFMEMORY; goto CleanErr; } // Don't treat error from this function as fatal GetComputerName(szLocalComputerName, &cbLocalComputerName); for (i = 0, pchServer = szServers; (i < (*pcServers)) && (pchServer != NULL) && (*pchServer != L'\0'); pchServer = wcschr(pchServer,L'\0')+1, i++) { (*prgwszServers)[i] = pchServer; if ((iLocalComputer == (DWORD)(-1)) && (wcscmp(pchServer,szLocalComputerName) == 0)) { iLocalComputer = i; } } // // Put local computer at head of list // if (iLocalComputer != (DWORD)(-1)) { if (iLocalComputer != 0) { // // Swap # iLocalComputer with # 0 // pchServer = (*prgwszServers)[iLocalComputer]; (*prgwszServers)[iLocalComputer] = (*prgwszServers)[0]; (*prgwszServers)[0] = pchServer; } RandomizeArray((*prgwszServers)+1,(*pcServers) - 1); } else { RandomizeArray((*prgwszServers),*pcServers); } *ppwszServerNames = szServers; CleanErr: if (FAILED(hr)) { if (NULL != szServers) { LocalFree(szServers); } if (NULL != *prgwszServers) { LocalFree(*prgwszServers); } } if (hKey != NULL) { RegCloseKey(hKey); } return hr; } HRESULT WriteLicenseServersToReg(LPWSTR wszRegKey, LPWSTR pwszServerNames,DWORD cchServers) { HRESULT hr = S_OK; HKEY hKey = NULL; DWORD dwType = REG_MULTI_SZ; DWORD dwErr; DWORD dwDisp; // // Delete the value // dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(LSERVER_DISCOVERY_PARAMETER_KEY), 0, KEY_WRITE, &hKey); if (dwErr == ERROR_SUCCESS) { RegDeleteValue(hKey,wszRegKey); } if ((pwszServerNames == NULL) || (cchServers < 2)) { hr = S_OK; goto CleanErr; } if(hKey != NULL) { RegCloseKey(hKey); hKey = NULL; } dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT(LSERVER_DISCOVERY_PARAMETER_KEY), 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp); if (dwErr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(dwErr); goto CleanErr; } dwErr = RegSetValueEx(hKey, wszRegKey, 0, dwType, (CONST BYTE *)pwszServerNames, cchServers*sizeof(WCHAR)); if (dwErr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(dwErr); goto CleanErr; } CleanErr: if (hKey != NULL) { RegCloseKey(hKey); } return hr; } // // Free pszDomain using NetApiBufferFree // DWORD WINAPI TLSInDomain(BOOL *pfInDomain, LPWSTR *pszDomain) { NET_API_STATUS dwErr; DSROLE_PRIMARY_DOMAIN_INFO_BASIC *pDomainInfo = NULL; PDOMAIN_CONTROLLER_INFO pdcInfo = NULL; if (pfInDomain == NULL) { return ERROR_INVALID_PARAMETER; } *pfInDomain = FALSE; // // Check if we're in a workgroup // dwErr = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *) &pDomainInfo); if ((dwErr != NO_ERROR) || (pDomainInfo == NULL)) { return dwErr; } switch (pDomainInfo->MachineRole) { case DsRole_RoleStandaloneWorkstation: case DsRole_RoleStandaloneServer: DsRoleFreeMemory(pDomainInfo); if (NULL != pszDomain) { NETSETUP_JOIN_STATUS BufferType; dwErr = NetGetJoinInformation(NULL,pszDomain,&BufferType); } return dwErr; break; // just in case } DsRoleFreeMemory(pDomainInfo); dwErr = DsGetDcName(NULL, // Computer Name NULL, // Domain Name NULL, // Domain GUID NULL, // Site Name DS_DIRECTORY_SERVICE_PREFERRED, &pdcInfo); if ((dwErr != NO_ERROR) || (pdcInfo == NULL)) { if (dwErr == ERROR_NO_SUCH_DOMAIN) { *pfInDomain = FALSE; return NO_ERROR; } else { if (pdcInfo == NULL) dwErr = ERROR_INTERNAL_ERROR; return dwErr; } } if (pdcInfo->Flags & DS_DS_FLAG) { *pfInDomain = TRUE; } if (pszDomain != NULL) { dwErr = NetApiBufferAllocate((wcslen(pdcInfo->DomainName)+1) * sizeof(WCHAR), (LPVOID *)pszDomain); if ((NERR_Success == dwErr) && (NULL != *pszDomain)) { wcscpy(*pszDomain,pdcInfo->DomainName); } } if (pdcInfo != NULL) NetApiBufferFree(pdcInfo); return dwErr; } /*++ Function: LicenseServerCachingThread Description: This is the thread that does the license server caching. Arguments: lpParam - contains the exit event handle Returns: Always 1 --*/ DWORD WINAPI LicenseServerCachingThread( LPVOID lpParam ) { DWORD dwWaitStatus; HANDLE hExit = (HANDLE)lpParam; DWORD dwDiscoveryInterval = DISCOVERY_INTERVAL; HANDLE rgWaitHandles[] = {hExit,g_hImmediateDiscovery,g_hDiscoverySoon}; BOOL bFoundServer; BOOL bSkipOne = FALSE; HANDLE hEvent; // // Yield our time slice to other threads now, so that the terminal server // service can start up quickly. Refresh the license server cache when we // resume our time slice. // Sleep( 0 ); while (1) { if (!bSkipOne) { bFoundServer = TLSRefreshLicenseServerCache(INFINITE); if ((!g_fOffSiteLicenseServer) && bFoundServer) { dwDiscoveryInterval = INFINITE; } } else { bSkipOne = FALSE; } dwWaitStatus = WaitForMultipleObjects( sizeof(rgWaitHandles) / sizeof(HANDLE), rgWaitHandles, FALSE, // wait for any one event dwDiscoveryInterval); if (WAIT_OBJECT_0 == dwWaitStatus) { // hExit was signalled goto done; } if ((WAIT_OBJECT_0+1) == dwWaitStatus) { // g_hImmediateDiscovery was signalled // reduce dwDiscoveryInterval dwDiscoveryInterval = DISCOVERY_INTERVAL; } if ((WAIT_OBJECT_0+2) == dwWaitStatus) { // g_hDiscoverySoon was signalled // reduce dwDiscoveryInterval, but wait one round dwDiscoveryInterval = DISCOVERY_INTERVAL; bSkipOne = TRUE; } // we timed out, or hImmediateDiscovery was signalled. Re-start // discovery } done: hEvent = g_hCachingThreadExit; g_hCachingThreadExit = NULL; CloseHandle(hEvent); hEvent = g_hImmediateDiscovery; g_hImmediateDiscovery = NULL; CloseHandle(hEvent); hEvent = g_hDiscoverySoon; g_hDiscoverySoon = NULL; CloseHandle(hEvent); return 1; } extern "C" void TLSShutdown() { if (0 < InterlockedDecrement(&lLibUsage)) { // // Someone else is using it // return; } TLSStopDiscovery(); if (NULL != g_pRpcIdentity) { PSEC_WINNT_AUTH_IDENTITY pRpcIdentity = g_pRpcIdentity; g_pRpcIdentity = NULL; if (NULL != pRpcIdentity->User) { LocalFree(pRpcIdentity->User); } LocalFree(pRpcIdentity); } // // Cleanup random number generator // TSRNG_Shutdown(); LsCsp_Exit(); } extern "C" DWORD WINAPI TLSInit() { LICENSE_STATUS status; BOOL fInDomain = FALSE; if (0 != InterlockedExchangeAdd(&lLibUsage,1)) { // // Already been initialized // return ERROR_SUCCESS; } status = LsCsp_Initialize(); if (LICENSE_STATUS_OK != status) { InterlockedDecrement(&lLibUsage); switch (status) { case LICENSE_STATUS_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY; case LICENSE_STATUS_NO_CERTIFICATE: return SCARD_E_CERTIFICATE_UNAVAILABLE; case LICENSE_STATUS_INVALID_CERTIFICATE: return CERT_E_MALFORMED; default: return E_FAIL; } } if ((NO_ERROR == TLSInDomain(&fInDomain, NULL)) && (fInDomain) && (IsSystemService())) { // // We're running as SYSTEM // Create an RPC identity for use as an RPC client // g_pRpcIdentity = (PSEC_WINNT_AUTH_IDENTITY) LocalAlloc(LPTR, sizeof(SEC_WINNT_AUTH_IDENTITY)); if (NULL != g_pRpcIdentity) { g_pRpcIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; g_pRpcIdentity->UserLength = MAX_COMPUTERNAME_LENGTH + 2; g_pRpcIdentity->User = (WCHAR *) LocalAlloc(LPTR, g_pRpcIdentity->UserLength * sizeof(WCHAR)); if (NULL != g_pRpcIdentity->User) { if (GetComputerNameEx(ComputerNamePhysicalNetBIOS,g_pRpcIdentity->User,&(g_pRpcIdentity->UserLength))) { if (g_pRpcIdentity->UserLength < MAX_COMPUTERNAME_LENGTH + 1) { g_pRpcIdentity->User[g_pRpcIdentity->UserLength++] = L'$'; g_pRpcIdentity->User[g_pRpcIdentity->UserLength] = 0; } else { LocalFree(g_pRpcIdentity->User); LocalFree(g_pRpcIdentity); g_pRpcIdentity = NULL; InterlockedDecrement(&lLibUsage); return E_FAIL; } } else { LocalFree(g_pRpcIdentity->User); LocalFree(g_pRpcIdentity); g_pRpcIdentity = NULL; InterlockedDecrement(&lLibUsage); return GetLastError(); } } else { LocalFree(g_pRpcIdentity); g_pRpcIdentity = NULL; InterlockedDecrement(&lLibUsage); return ERROR_NOT_ENOUGH_MEMORY; } } else { InterlockedDecrement(&lLibUsage); return ERROR_NOT_ENOUGH_MEMORY; } } // // Init random number generator // TSRNG_Initialize(); return ERROR_SUCCESS; } extern "C" DWORD WINAPI TLSStartDiscovery() { HANDLE hCachingThread = NULL; HANDLE hEvent; if (NULL != g_hCachingThreadExit) { // already started return ERROR_SUCCESS; } // // Create the event to signal thread exit // g_hCachingThreadExit = CreateEvent( NULL, FALSE, FALSE, NULL ); if( NULL == g_hCachingThreadExit ) { return GetLastError(); } g_hImmediateDiscovery = CreateEvent(NULL,FALSE,FALSE,NULL); if (NULL == g_hImmediateDiscovery) { hEvent = g_hCachingThreadExit; g_hCachingThreadExit = NULL; CloseHandle(hEvent); return GetLastError(); } g_hDiscoverySoon = CreateEvent(NULL,FALSE,FALSE,NULL); if (NULL == g_hDiscoverySoon) { hEvent = g_hCachingThreadExit; g_hCachingThreadExit = NULL; CloseHandle(hEvent); hEvent = g_hImmediateDiscovery; g_hImmediateDiscovery = NULL; CloseHandle(hEvent); return GetLastError(); } // // Create the caching thread // hCachingThread = CreateThread( NULL, 0, LicenseServerCachingThread, ( LPVOID )g_hCachingThreadExit, 0, NULL ); if (hCachingThread == NULL) { hEvent = g_hCachingThreadExit; g_hCachingThreadExit = NULL; CloseHandle(hEvent); hEvent = g_hImmediateDiscovery; g_hImmediateDiscovery = NULL; CloseHandle(hEvent); hEvent = g_hDiscoverySoon; g_hDiscoverySoon = NULL; CloseHandle(hEvent); return GetLastError(); } CloseHandle(hCachingThread); return ERROR_SUCCESS; } extern "C" DWORD WINAPI TLSStopDiscovery() { // // Signal the thread to exit // if (NULL != g_hCachingThreadExit) { SetEvent( g_hCachingThreadExit ); } return ERROR_SUCCESS; } // // Number of DCs to allocate space for at a time // #define DC_LIST_CHUNK 10 //+------------------------------------------------------------------------ // Function: // // EnumerateLsServer() // // Description: // // Routine to enumerate all hydra license server in network // // Arguments: // // szScope - Scope limit, NULL if doen't care. // dwPlatformType - verify if license server have licenses for this platform, // LSKEYPACKPLATFORMTYPE_UNKNOWN if doesn't care. // fCallBack - call back routine when EnumerateServer() founds any server, // dwUserData - data to be pass to call back routine // // Return Value: // // RPC_S_OK or any RPC specific error code. // // NOTE: // // Enumeration terminate when either there is no more server or call back // routine return TRUE. // //------------------------------------------------------------------------- DWORD WINAPI EnumerateTlsServerInDomain( IN LPCTSTR szDomain, IN TLSENUMERATECALLBACK fCallBack, IN HANDLE dwUserData, IN DWORD dwTimeOut, IN BOOL fRegOnly, IN OUT BOOL *pfOffSite ) /*++ ++*/ { DWORD entriesread = 0; BOOL bCancel=FALSE; DWORD dwErrCode; LPWSTR pwszServerTmp = NULL; LPWSTR pwszServer = NULL; HRESULT hr; LPWSTR pwszServers = NULL; LPWSTR pwszServersTmp = NULL; DWORD cchServers = 0; DWORD cchServer; LPWSTR *rgwszServers = NULL; LPWSTR *rgwszServersTmp; LPWSTR pwszServerNames = NULL; DWORD dwErr = ERROR_SUCCESS, i; HANDLE hDcOpen = NULL; LPWSTR szSiteName = NULL; BOOL fOffSiteIn; BOOL fFoundOne = FALSE; BOOL fFoundOneOffSite = FALSE; DWORD cChunks = 0; DWORD cServersOnSite = 0; if (fRegOnly) { // // check for a license server in the registry // hr = GetLicenseServersFromReg(REG_DOMAIN_SERVER_MULTI,&pwszServerNames,&entriesread,&rgwszServers); if (FAILED(hr)) { dwErr = hr; goto Cleanup; } } else { if (NULL == pfOffSite) { return ERROR_INVALID_PARAMETER; } fOffSiteIn = *pfOffSite; *pfOffSite = FALSE; dwErr = DsGetSiteName(NULL,&szSiteName); if(dwErr != ERROR_SUCCESS) { #ifdef PRIVATEDEBUG wprintf(L"DsGetSiteName failed %x\n",dwErr); #endif goto Cleanup; } dwErr = DsGetDcOpenW(szDomain, fOffSiteIn ? DS_NOTIFY_AFTER_SITE_RECORDS: DS_ONLY_DO_SITE_NAME, szSiteName, NULL, // DomainGuid NULL, // DnsForestName 0, // Flags &hDcOpen ); if(dwErr != ERROR_SUCCESS) { #ifdef PRIVATEDEBUG wprintf(L"DsGetDcOpen failed %x\n",dwErr); #endif goto Cleanup; } rgwszServers = (LPWSTR *) LocalAlloc(LPTR, DC_LIST_CHUNK * sizeof(LPWSTR)); if (NULL == rgwszServers) { #ifdef PRIVATEDEBUG wprintf(L"Out of memory\n"); #endif dwErr = E_OUTOFMEMORY; goto Cleanup; } cChunks = 1; // // Read the whole DC list // do { if (entriesread >= (cChunks * DC_LIST_CHUNK)) { cChunks++; rgwszServersTmp = (LPWSTR *) LocalReAlloc(rgwszServers, DC_LIST_CHUNK * sizeof(LPWSTR) * cChunks, LHND); if (NULL == rgwszServersTmp) { dwErr = E_OUTOFMEMORY; goto Cleanup; } else { rgwszServers = rgwszServersTmp; } } dwErr = DsGetDcNextW(hDcOpen, NULL, NULL, rgwszServers+entriesread); if (ERROR_FILEMARK_DETECTED == dwErr) { // Now going off-site; use NULL ptr marker rgwszServers[entriesread] = NULL; cServersOnSite = entriesread; dwErr = ERROR_SUCCESS; fFoundOneOffSite = TRUE; } entriesread++; } while (ERROR_SUCCESS == dwErr); // don't count the final error entriesread--; if (!fFoundOneOffSite) cServersOnSite = entriesread; // Now randomize the two portions of the array RandomizeArray(rgwszServers,cServersOnSite); if (fFoundOneOffSite) { RandomizeArray(rgwszServers+cServersOnSite+1, entriesread - cServersOnSite - 1); } // Now allocate memory for registry entry pwszServers = (LPWSTR) LocalAlloc(LPTR,2*sizeof(WCHAR)); if (NULL == pwszServers) { #ifdef PRIVATEDEBUG wprintf(L"Out of memory\n"); #endif dwErr = E_OUTOFMEMORY; goto Cleanup; } cchServers = 2; pwszServers[0] = pwszServers[1] = L'\0'; } for(i=0; bCancel == FALSE; i++) { PCONTEXT_HANDLE pContext=NULL; RPC_STATUS rpcStatus; if (!fRegOnly) { if (fFoundOneOffSite && i == cServersOnSite) { if (fFoundOne) break; // Now going off-site i++; *pfOffSite = TRUE; } } if (i >= entriesread) break; pwszServerTmp = rgwszServers[i]; bCancel=fCallBack(pContext, pwszServerTmp, dwUserData); if(bCancel == TRUE) continue; if(!(pContext = TLSConnectToLsServer(pwszServerTmp))) { // // could be access denied. // #ifdef PRIVATEDEBUG wprintf(L"Can't connect to %s\n",pwszServerTmp); #endif continue; } #ifdef PRIVATEDEBUG wprintf(L"!!!Connected to %s\n",pwszServerTmp); #endif do { // // Skip enterprise server // DWORD dwVersion; rpcStatus = TLSGetVersion( pContext, &dwVersion ); if(rpcStatus != RPC_S_OK) { break; } #if ENFORCE_LICENSING // // W2K Beta 3 to RC1 upgrade, don't connect to any non-enforce // server 5.2 or older // if(IS_ENFORCE_LSSERVER(dwVersion) == FALSE) { if( GET_LSSERVER_MAJOR_VERSION(dwVersion) <= 5 && GET_LSSERVER_MINOR_VERSION(dwVersion) <= 2 ) { continue; } } // // Prevent beta <-> RTM server talking to each other // // // TLSIsBetaNTServer() returns TRUE if eval NT // IS_LSSERVER_RTM() returns TRUE if LS is an RTM. // if( TLSIsBetaNTServer() == IS_LSSERVER_RTM(dwVersion) ) { continue; } #endif if(dwVersion & TLS_VERSION_ENTERPRISE_BIT) { continue; } bCancel=fCallBack(pContext, pwszServerTmp, dwUserData); if (!fRegOnly) { // // Add to list of servers // cchServer = wcslen(pwszServerTmp); pwszServersTmp = (LPWSTR) LocalReAlloc(pwszServers,(cchServers+cchServer+1)*sizeof(TCHAR),LHND); if (NULL == pwszServersTmp) { break; } pwszServers = pwszServersTmp; if (cchServers == 2) { wcscpy(pwszServers,pwszServerTmp); cchServers += cchServer; } else { wcscpy(pwszServers+cchServers-1,pwszServerTmp); cchServers += cchServer + 1; } pwszServers[cchServers-1] = L'\0'; } fFoundOne = TRUE; } while (FALSE); if(bCancel == FALSE && pContext != NULL) { TLSDisconnect(&pContext); } } // for loop if (!fRegOnly) { WriteLicenseServersToReg(REG_DOMAIN_SERVER_MULTI,pwszServers,cchServers); } Cleanup: if (NULL != hDcOpen) DsGetDcCloseW(hDcOpen); if (NULL != rgwszServers) { if (!fRegOnly) { for (i = 0; i < entriesread; i++) { if (NULL != rgwszServers[i]) { NetApiBufferFree(rgwszServers[i]); } } } LocalFree(rgwszServers); } if (szSiteName) NetApiBufferFree(szSiteName); if (pwszServerNames) LocalFree(pwszServerNames); if (pwszServers) LocalFree(pwszServers); if (pwszServer) LocalFree(pwszServer); return dwErr; } DWORD WINAPI EnumerateTlsServerInWorkGroup( IN TLSENUMERATECALLBACK pfCallBack, IN HANDLE dwUserData, IN DWORD dwTimeOut, IN BOOL fRegOnly ) /*++ ++*/ { DWORD dwStatus=ERROR_SUCCESS; TCHAR szServerMailSlotName[MAX_PATH+1]; TCHAR szLocalMailSlotName[MAX_PATH+1]; HANDLE hClientSlot = INVALID_HANDLE_VALUE; HANDLE hServerSlot = INVALID_HANDLE_VALUE; TCHAR szDiscMsg[MAX_MAILSLOT_MSG_SIZE+1]; TCHAR szComputerName[MAXCOMPUTERNAMELENGTH+1]; TCHAR szRandomMailSlotName[MAXCOMPUTERNAMELENGTH+1]; DWORD cbComputerName=MAXCOMPUTERNAMELENGTH+1; DWORD cbWritten=0; DWORD cbRead=0; BOOL bCancel = FALSE; DWORD dwErrCode; HRESULT hr; LPWSTR pwszServers = NULL; LPWSTR pwszServersTmp = NULL; DWORD cchServers = 0; DWORD cchServer; LPWSTR *rgwszServers = NULL; LPWSTR pwszServerNames = NULL; DWORD cServers = 0; DWORD i = 0; LPWSTR pwszServerTmp = szComputerName; if (!fRegOnly) { if(!GetComputerName(szComputerName, &cbComputerName)) { dwStatus = GetLastError(); goto cleanup; } if (0 == (1 & GetSystemMetrics(SM_NETWORK))) { // No network; try local machine #ifdef PRIVATEDEBUG wprintf(L"No network, trying local computer=%s\n",szComputerName); #endif dwStatus = ERROR_SUCCESS; goto TryServer; } wsprintf( szRandomMailSlotName, _TEXT("%08x"), GetCurrentThreadId() ); _stprintf( szLocalMailSlotName, _TEXT("\\\\.\\mailslot\\%s"), szRandomMailSlotName ); // // Create local mail slot for server's response // hClientSlot=CreateMailslot( szLocalMailSlotName, 0, (dwTimeOut == MAILSLOT_WAIT_FOREVER) ? 5 * 1000: dwTimeOut, NULL ); if(hClientSlot == INVALID_HANDLE_VALUE) { dwStatus = GetLastError(); goto cleanup; } // // Open server's mail slot // _stprintf( szServerMailSlotName, _TEXT("\\\\%s\\mailslot\\%s"), _TEXT("*"), _TEXT(SERVERMAILSLOTNAME) ); hServerSlot=CreateFile( szServerMailSlotName, GENERIC_WRITE, // only need write FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if(hServerSlot == INVALID_HANDLE_VALUE) { dwStatus = GetLastError(); goto cleanup; } // // Formulate discovery message // _stprintf( szDiscMsg, _TEXT("%s %c%s%c %c%s%c"), _TEXT(LSERVER_DISCOVERY), _TEXT(LSERVER_OPEN_BLK), szComputerName, _TEXT(LSERVER_CLOSE_BLK), _TEXT(LSERVER_OPEN_BLK), szRandomMailSlotName, _TEXT(LSERVER_CLOSE_BLK) ); if (!WriteFile(hServerSlot, szDiscMsg, (_tcslen(szDiscMsg) + 1) * sizeof(TCHAR), &cbWritten, NULL) || (cbWritten != (_tcslen(szDiscMsg) + 1 ) * sizeof(TCHAR))) { dwStatus = GetLastError(); if (dwStatus == ERROR_NETWORK_UNREACHABLE) { // No network; try local machine #ifdef PRIVATEDEBUG wprintf(L"No network, trying local computer=%s\n",szComputerName); #endif dwStatus = ERROR_SUCCESS; goto TryServer; } else { goto cleanup; } } // Allocate for registry entry pwszServers = (LPWSTR) LocalAlloc(LPTR,2*sizeof(WCHAR)); if (NULL == pwszServers) { #ifdef PRIVATEDEBUG wprintf(L"Out of memory\n"); #endif dwStatus = E_OUTOFMEMORY; goto cleanup; } cchServers = 2; pwszServers[0] = pwszServers[1] = L'\0'; } else { // // check for a license server in the registry // hr = GetLicenseServersFromReg(REG_DOMAIN_SERVER_MULTI,&pwszServerNames,&cServers,&rgwszServers); if (FAILED(hr)) { dwStatus = hr; goto cleanup; } } do { if(fRegOnly) { if (i >= cServers) { break; } pwszServerTmp = rgwszServers[i++]; } else { memset(szComputerName, 0, sizeof(szComputerName)); if(!ReadFile(hClientSlot, szComputerName, sizeof(szComputerName) - sizeof(TCHAR), &cbRead, NULL)) { dwStatus=GetLastError(); break; } #ifdef PRIVATEDEBUG wprintf(L"Trying server=%s\n",szComputerName); #endif } TryServer: bCancel=pfCallBack(NULL, pwszServerTmp, dwUserData); if(bCancel == TRUE) { continue; } PCONTEXT_HANDLE pContext=NULL; RPC_STATUS rpcStatus; if(!(pContext = TLSConnectToLsServer(pwszServerTmp))) { // // could be access denied. // continue; } do { // // Skip enterprise server // DWORD dwVersion; rpcStatus = TLSGetVersion( pContext, &dwVersion ); if(rpcStatus != RPC_S_OK) { continue; } #if ENFORCE_LICENSING // // W2K Beta 3 to RC1 upgrade, don't connect to any non-enforce // server 5.2 or older // if(IS_ENFORCE_LSSERVER(dwVersion) == FALSE) { if( GET_LSSERVER_MAJOR_VERSION(dwVersion) <= 5 && GET_LSSERVER_MINOR_VERSION(dwVersion) <= 2 ) { 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; } #endif if(dwVersion & TLS_VERSION_ENTERPRISE_BIT) { continue; } bCancel=pfCallBack(pContext, pwszServerTmp, dwUserData); if (!fRegOnly) { // // Add to list of servers // cchServer = wcslen(pwszServerTmp); pwszServersTmp = (LPWSTR) LocalReAlloc(pwszServers,(cchServers+cchServer+1)*sizeof(TCHAR),LHND); if (NULL == pwszServersTmp) { continue; } pwszServers = pwszServersTmp; if (cchServers == 2) { wcscpy(pwszServers,pwszServerTmp); cchServers += cchServer; } else { wcscpy(pwszServers+cchServers-1,pwszServerTmp); cchServers += cchServer + 1; } pwszServers[cchServers-1] = L'\0'; } } while (FALSE); if(bCancel == FALSE && pContext != NULL) { TLSDisconnectFromServer(pContext); } } while(bCancel == FALSE); if (!fRegOnly) { WriteLicenseServersToReg(REG_DOMAIN_SERVER_MULTI,pwszServers,cchServers); } cleanup: if(hClientSlot != INVALID_HANDLE_VALUE) { CloseHandle(hClientSlot); } if(hServerSlot != INVALID_HANDLE_VALUE) { CloseHandle(hServerSlot); } if (pwszServerNames) LocalFree(pwszServerNames); if (pwszServers) LocalFree(pwszServers); if (rgwszServers) LocalFree(rgwszServers); return dwStatus; } DWORD GetServersFromRegistry( LPWSTR wszRegKey, LPWSTR **prgszServers, DWORD *pcCount ) { HKEY hParamKey = NULL; DWORD dwValueType; DWORD cbValue = 0, dwDisp; LONG lReturn; DWORD cbServer; DWORD cServers; DWORD cchServerMax; LPWSTR *rgszServers; DWORD i, j; *prgszServers = NULL; *pcCount = 0; lReturn = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hParamKey ); if (ERROR_SUCCESS != lReturn) return lReturn; lReturn = RegQueryInfoKey(hParamKey, NULL, NULL, NULL, &cServers, &cchServerMax, NULL, NULL, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS != lReturn) { RegCloseKey( hParamKey ); return lReturn; } if (0 == cServers) { RegCloseKey( hParamKey ); return ERROR_NO_MORE_ITEMS; } rgszServers = (LPWSTR *) LocalAlloc(LPTR,cServers*sizeof(LPWSTR)); if (NULL == rgszServers) { RegCloseKey( hParamKey ); return ERROR_NOT_ENOUGH_MEMORY; } // Add one for null terminator cchServerMax++; for (i = 0; i < cServers; i++) { rgszServers[i] = (LPWSTR) LocalAlloc(LPTR,cchServerMax * sizeof(WCHAR)); if (NULL == rgszServers[i]) { for (j = 0; j < i; j++) { LocalFree(rgszServers[j]); } LocalFree(rgszServers); RegCloseKey( hParamKey ); return ERROR_NOT_ENOUGH_MEMORY; } cbServer = cchServerMax * sizeof(WCHAR); lReturn = RegEnumKeyEx(hParamKey, i, rgszServers[i], &cbServer, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS != lReturn) { for (j = 0; j <= i; j++) { LocalFree(rgszServers[j]); } LocalFree(rgszServers); RegCloseKey( hParamKey ); return lReturn; } } *prgszServers = rgszServers; *pcCount = cServers; return ERROR_SUCCESS; } DWORD WINAPI EnumerateTlsServerInRegistry( IN TLSENUMERATECALLBACK pfCallBack, IN HANDLE dwUserData, IN DWORD dwTimeOut, LPWSTR wszRegKey ) /*++ ++*/ { BOOL bCancel=FALSE; DWORD dwIndex = 0; DWORD cServers = 0; LPWSTR *rgszServers = NULL; DWORD lReturn; lReturn = GetServersFromRegistry(wszRegKey, &rgszServers, &cServers ); if (ERROR_SUCCESS != lReturn) { return lReturn; } RandomizeArray(rgszServers,cServers); for (;dwIndex < cServers; dwIndex++) { PCONTEXT_HANDLE pContext=NULL; RPC_STATUS rpcStatus; bCancel=pfCallBack(pContext, rgszServers[dwIndex], dwUserData); if(bCancel == TRUE) continue; if(!(pContext = TLSConnectToLsServer(rgszServers[dwIndex]))) { // // could be access denied, or the machine is gone // continue; } do { // // Skip enterprise server // DWORD dwVersion; rpcStatus = TLSGetVersion( pContext, &dwVersion ); if(rpcStatus != RPC_S_OK) { break; } #if ENFORCE_LICENSING // // W2K Beta 3 to RC1 upgrade, don't connect to any non-enforce // server 5.2 or older // if(IS_ENFORCE_LSSERVER(dwVersion) == FALSE) { if( GET_LSSERVER_MAJOR_VERSION(dwVersion) <= 5 && GET_LSSERVER_MINOR_VERSION(dwVersion) <= 2 ) { // old License Server continue; } } // // Prevent beta <-> RTM server talking to each other // // // TLSIsBetaNTServer() returns TRUE if eval NT // IS_LSSERVER_RTM() returns TRUE if LS is an RTM. // if( TLSIsBetaNTServer() == IS_LSSERVER_RTM(dwVersion) ) { continue; } #endif bCancel=pfCallBack(pContext, rgszServers[dwIndex], dwUserData); } while (FALSE); if(bCancel == FALSE && pContext != NULL) { TLSDisconnect(&pContext); } } // for loop for (dwIndex = 0; dwIndex < cServers; dwIndex++) { LocalFree(rgszServers[dwIndex]); } LocalFree(rgszServers); return ERROR_SUCCESS; } DWORD WINAPI EnumerateTlsServer( IN TLSENUMERATECALLBACK pfCallBack, IN HANDLE dwUserData, IN DWORD dwTimeOut, IN BOOL fRegOnly ) /*++ ++*/ { DWORD dwErr; LPWSTR szDomain = NULL; BOOL fOffSite = FALSE; // don't try to go off-site // // First check for a registry bypass of discovery // dwErr = EnumerateTlsServerInRegistry( pfCallBack, dwUserData, dwTimeOut, TEXT(TERMINAL_SERVICE_PARAM_DISCOVERY) ); if ((!fRegOnly) || (g_fInDomain == -1)) { // // Check even if set (for !fRegOnly), to get domain name // dwErr = TLSInDomain(&g_fInDomain, fRegOnly ? NULL : &szDomain); if (dwErr != NO_ERROR) return dwErr; } // // Reading registry failed, use full discovery // if(g_fInDomain) { dwErr = EnumerateTlsServerInDomain( szDomain, pfCallBack, dwUserData, dwTimeOut, fRegOnly, &fOffSite ); if ((dwErr == NO_ERROR) && !fRegOnly) { g_fOffSiteLicenseServer = fOffSite; } } else { dwErr = EnumerateTlsServerInWorkGroup( pfCallBack, dwUserData, dwTimeOut, fRegOnly ); } if (NULL != szDomain) { NetApiBufferFree(szDomain); } if ((NULL != g_hImmediateDiscovery) && (dwErr != NO_ERROR) && fRegOnly) { SetEvent(g_hImmediateDiscovery); } if ((NULL != g_hDiscoverySoon) && (dwErr == NO_ERROR) && fOffSite && !fRegOnly) { SetEvent(g_hDiscoverySoon); } return dwErr; } TLS_HANDLE ConnectAndCheckServer(LPWSTR szServer) { TLS_HANDLE hBinding; DWORD dwVersion; RPC_STATUS rpcStatus; hBinding = TLSConnectToLsServer(szServer); if(hBinding == NULL) { goto done; } // Skip Windows 2000 License servers DWORD dwSupportFlags = 0; DWORD dwErrCode = 0; dwErrCode = TLSGetSupportFlags( hBinding, &dwSupportFlags ); if ((dwErrCode == RPC_S_OK) && !(dwSupportFlags & SUPPORT_WHISTLER_CAL)) { TLSDisconnect(&hBinding); goto done; } // If the call fails => Windows 2000 LS else if(dwErrCode != RPC_S_OK) { TLSDisconnect(&hBinding); goto done; } rpcStatus = TLSGetVersion( hBinding, &dwVersion ); if(rpcStatus != RPC_S_OK) { TLSDisconnect(&hBinding); goto done; } if( TLSIsBetaNTServer() == IS_LSSERVER_RTM(dwVersion) ) { TLSDisconnect(&hBinding); goto done; } done: return hBinding; } //+------------------------------------------------------------------------ // Function: TLSConnectToAnyLsServer() // // Description: // // Routine to bind to any license server // // Arguments: // dwTimeout - INFINITE for going off-site // // Return Value: // // RPC binding handle or NULL if error, use GetLastError() to retrieve // detail error. //------------------------------------------------------------------------- TLS_HANDLE WINAPI TLSConnectToAnyLsServer( DWORD dwTimeout ) /*++ ++*/ { TLS_HANDLE hBinding=NULL; HRESULT hr = S_OK; LPWSTR *rgszServers = NULL; DWORD cServers = 0; DWORD i; DWORD dwErr; BOOL fInDomain; LPWSTR szDomain = NULL; LPWSTR szServerFound = NULL; BOOL fRegOnly = (dwTimeout != INFINITE); LPWSTR pwszServerNames = NULL; BOOL fFreeServerNames = TRUE; // TODO: add error codes/handling to all of this // // First check for a registry bypass of discovery // dwErr = GetServersFromRegistry( TEXT(TERMINAL_SERVICE_PARAM_DISCOVERY), &rgszServers, &cServers ); if (ERROR_SUCCESS == dwErr) { RandomizeArray(rgszServers,cServers); for (i = 0; i < cServers; i++) { hBinding = ConnectAndCheckServer(rgszServers[i]); if (NULL != hBinding) { szServerFound = rgszServers[i]; goto found_one; } } if(NULL != rgszServers) { for (i = 0; i < cServers; i++) { LocalFree(rgszServers[i]); } LocalFree(rgszServers); rgszServers = NULL; } } // // Next try Site (Enterprise) license servers // if (!fRegOnly) { hr = GetAllEnterpriseServers(&rgszServers,&cServers); if (SUCCEEDED(hr)) { RandomizeArray(rgszServers,cServers); } } else { // rgszServers[i] is an index into pwszServerNames; don't free fFreeServerNames = FALSE; hr = GetLicenseServersFromReg(ENTERPRISE_SERVER_MULTI, &pwszServerNames, &cServers, &rgszServers); } if (SUCCEEDED(hr)) { for (i = 0; i < cServers; i++) { hBinding = ConnectAndCheckServer(rgszServers[i]); if (NULL != hBinding) { szServerFound = rgszServers[i]; goto found_one; } } if(NULL != rgszServers) { if (fFreeServerNames) { for (i = 0; i < cServers; i++) { LocalFree(rgszServers[i]); } LocalFree(rgszServers); } rgszServers = NULL; } } // // No Site LS found, try Domain/Workgroup servers // dwErr = TLSInDomain(&fInDomain, &szDomain); if (dwErr != NO_ERROR) { return NULL; } LS_ENUM_PARAM param; param.hBinding = &hBinding; param.dwTimeout = INFINITE; QueryPerformanceCounter(&(param.timeInitial)); fFreeServerNames = TRUE; if (fInDomain) { BOOL fOffSite = TRUE; dwErr = EnumerateTlsServerInDomain( szDomain, BindAnyServer, ¶m, INFINITE, fRegOnly, &fOffSite ); if (dwErr == NO_ERROR) { g_fOffSiteLicenseServer = fOffSite; } } else { dwErr = EnumerateTlsServerInWorkGroup( BindAnyServer, ¶m, MAILSLOT_WAIT_FOREVER, fRegOnly ); } if (NULL != szDomain) { NetApiBufferFree(szDomain); } if (hBinding != NULL) goto found_one; if (NULL != pwszServerNames) { LocalFree(pwszServerNames); } if ((NULL != g_hImmediateDiscovery) && fRegOnly) { SetEvent(g_hImmediateDiscovery); } else if ((NULL != g_hDiscoverySoon) && !fRegOnly && g_fOffSiteLicenseServer) { SetEvent(g_hDiscoverySoon); } return NULL; found_one: if (NULL != pwszServerNames) { LocalFree(pwszServerNames); } if(NULL != rgszServers) { if (fFreeServerNames) { for (i = 0; i < cServers; i++) { LocalFree(rgszServers[i]); } } LocalFree(rgszServers); } return hBinding; } BOOL TLSRefreshLicenseServerCache( IN DWORD dwTimeOut ) /*++ Abstract: Refresh license server cache in registry. Parameter: dwTimeOut : Reserverd, should pass in INIFINITE for now Returns: TRUE/FALSE --*/ { BOOL bFoundServer = FALSE; TLS_HANDLE hBinding = NULL; hBinding = TLSConnectToAnyLsServer(dwTimeOut); if (NULL != hBinding) { bFoundServer = TRUE; TLSDisconnect(&hBinding); } return bFoundServer; } LICENSE_STATUS InstallCertificate(LPVOID lpParam) { Sleep(INSTALL_CERT_DELAY); return LsCsp_InstallX509Certificate(NULL); } //------------------------------------------------------------------------- TLS_HANDLE WINAPI TLSConnectToLsServer( LPTSTR pszLsServer ) /*++ ++*/ { TCHAR szMachineName[MAX_COMPUTERNAME_LENGTH + 1] ; PCONTEXT_HANDLE pContext=NULL; DWORD cbMachineName=MAX_COMPUTERNAME_LENGTH; HANDLE hThread = NULL; static BOOL fLSFound = FALSE; memset(szMachineName, 0, sizeof(szMachineName)); GetComputerName(szMachineName, &cbMachineName); if(pszLsServer == NULL || _tcsicmp(szMachineName, pszLsServer) == 0) { pContext=ConnectLsServer( szMachineName, _TEXT(RPC_PROTOSEQLPC), NULL, RPC_C_AUTHN_LEVEL_DEFAULT ); if(GetLastError() >= LSERVER_ERROR_BASE) { return NULL; } // try to connect with TCP protocol, if local procedure failed } if(pContext == NULL) { pContext=ConnectLsServer( pszLsServer, _TEXT(RPC_PROTOSEQNP), _TEXT(LSNAMEPIPE), RPC_C_AUTHN_LEVEL_PKT_PRIVACY ); } if (!fLSFound && (NULL != pContext)) { fLSFound = TRUE; // Now that someone's connected, we can install a license hThread = CreateThread(NULL, 0, InstallCertificate, NULL, 0, NULL); if (hThread != NULL) { CloseHandle(hThread); } else { // Can't create the thread; try again later fLSFound = FALSE; } } return (TLS_HANDLE) pContext; } //------------------------------------------------------------------------- void WINAPI TLSDisconnectFromServer( TLS_HANDLE pHandle ) /*++ ++*/ { if(pHandle != NULL) { TLSDisconnect( &pHandle ); } } //---------------------------------------------------------------------------- DWORD WINAPI TLSConnect( handle_t binding, TLS_HANDLE *ppHandle ) /*++ ++*/ { return TLSRpcConnect(binding, ppHandle); } //---------------------------------------------------------------------------- DWORD WINAPI TLSDisconnect( TLS_HANDLE* pphHandle ) /*++ ++*/ { RPC_STATUS rpc_status; rpc_status = TLSRpcDisconnect( pphHandle ); if(rpc_status != RPC_S_OK) { RpcSmDestroyClientContext(pphHandle); } *pphHandle = NULL; return ERROR_SUCCESS; } //------------------------------------------------------------------------- DWORD WINAPI TLSGetVersion ( IN TLS_HANDLE hHandle, OUT PDWORD pdwVersion ) /*++ ++*/ { return TLSRpcGetVersion( hHandle, pdwVersion ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSSendServerCertificate( TLS_HANDLE hHandle, DWORD cbCert, PBYTE pbCert, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcSendServerCertificate( hHandle, cbCert, pbCert, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetServerName( TLS_HANDLE hHandle, LPTSTR szMachineName, PDWORD pcbSize, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcGetServerName( hHandle, szMachineName, pcbSize, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetServerNameEx( TLS_HANDLE hHandle, LPTSTR szMachineName, PDWORD pcbSize, PDWORD pdwErrCode ) /*++ ++*/ { RPC_STATUS rpc_status; rpc_status = TLSRpcGetServerNameEx( hHandle, szMachineName, pcbSize, pdwErrCode ); if (rpc_status == RPC_S_PROCNUM_OUT_OF_RANGE) { rpc_status = TLSRpcGetServerName( hHandle, szMachineName, pcbSize, pdwErrCode ); } return rpc_status; } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetServerNameFixed( TLS_HANDLE hHandle, LPTSTR *pszMachineName, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcGetServerNameFixed( hHandle, pszMachineName, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetServerScope( TLS_HANDLE hHandle, LPTSTR szScopeName, PDWORD pcbSize, PDWORD pdwErrCode) /*++ ++*/ { return TLSRpcGetServerScope( hHandle, szScopeName, pcbSize, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetServerScopeFixed( TLS_HANDLE hHandle, LPTSTR *pszScopeName, PDWORD pdwErrCode) /*++ ++*/ { return TLSRpcGetServerScopeFixed( hHandle, pszScopeName, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSIssuePlatformChallenge( TLS_HANDLE hHandle, DWORD dwClientInfo, PCHALLENGE_CONTEXT pChallengeContext, PDWORD pcbChallengeData, PBYTE* pChallengeData, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcIssuePlatformChallenge( hHandle, dwClientInfo, pChallengeContext, pcbChallengeData, pChallengeData, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSIssueNewLicense( TLS_HANDLE hHandle, CHALLENGE_CONTEXT ChallengeContext, LICENSEREQUEST *pRequest, LPTSTR pMachineName, LPTSTR pUserName, DWORD cbChallengeResponse, PBYTE pbChallengeResponse, BOOL bAcceptTemporaryLicense, PDWORD pcbLicense, PBYTE* ppbLicense, PDWORD pdwErrCode ) /*++ ++*/ { TLSLICENSEREQUEST rpcRequest; RequestToTlsRequest( pRequest, &rpcRequest ); return TLSRpcRequestNewLicense( hHandle, ChallengeContext, &rpcRequest, pMachineName, pUserName, cbChallengeResponse, pbChallengeResponse, bAcceptTemporaryLicense, pcbLicense, ppbLicense, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSIssueNewLicenseEx( TLS_HANDLE hHandle, PDWORD pSupportFlags, CHALLENGE_CONTEXT ChallengeContext, LICENSEREQUEST *pRequest, LPTSTR pMachineName, LPTSTR pUserName, DWORD cbChallengeResponse, PBYTE pbChallengeResponse, BOOL bAcceptTemporaryLicense, DWORD dwQuantity, PDWORD pcbLicense, PBYTE* ppbLicense, PDWORD pdwErrCode ) /*++ ++*/ { DWORD dwStatus; TLSLICENSEREQUEST rpcRequest; RequestToTlsRequest( pRequest, &rpcRequest ); dwStatus = TLSRpcRequestNewLicenseEx( hHandle, pSupportFlags, ChallengeContext, &rpcRequest, pMachineName, pUserName, cbChallengeResponse, pbChallengeResponse, bAcceptTemporaryLicense, dwQuantity, pcbLicense, ppbLicense, pdwErrCode ); if (dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE) { *pSupportFlags = 0; dwStatus = TLSRpcRequestNewLicense( hHandle, ChallengeContext, &rpcRequest, pMachineName, pUserName, cbChallengeResponse, pbChallengeResponse, bAcceptTemporaryLicense, pcbLicense, ppbLicense, pdwErrCode ); } return(dwStatus); } //---------------------------------------------------------------------------- DWORD WINAPI TLSIssueNewLicenseExEx( TLS_HANDLE hHandle, PDWORD pSupportFlags, CHALLENGE_CONTEXT ChallengeContext, LICENSEREQUEST *pRequest, LPTSTR pMachineName, LPTSTR pUserName, DWORD cbChallengeResponse, PBYTE pbChallengeResponse, BOOL bAcceptTemporaryLicense, BOOL bAcceptFewerLicenses, DWORD *pdwQuantity, PDWORD pcbLicense, PBYTE* ppbLicense, PDWORD pdwErrCode ) /*++ ++*/ { DWORD dwStatus; TLSLICENSEREQUEST rpcRequest; RequestToTlsRequest( pRequest, &rpcRequest ); dwStatus = TLSRpcRequestNewLicenseExEx( hHandle, pSupportFlags, ChallengeContext, &rpcRequest, pMachineName, pUserName, cbChallengeResponse, pbChallengeResponse, bAcceptTemporaryLicense, bAcceptFewerLicenses, pdwQuantity, pcbLicense, ppbLicense, pdwErrCode ); if (dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE) { dwStatus = TLSRpcRequestNewLicenseEx( hHandle, pSupportFlags, ChallengeContext, &rpcRequest, pMachineName, pUserName, cbChallengeResponse, pbChallengeResponse, bAcceptTemporaryLicense, *pdwQuantity, pcbLicense, ppbLicense, pdwErrCode ); if (dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE) { *pSupportFlags = 0; dwStatus = TLSRpcRequestNewLicense( hHandle, ChallengeContext, &rpcRequest, pMachineName, pUserName, cbChallengeResponse, pbChallengeResponse, bAcceptTemporaryLicense, pcbLicense, ppbLicense, pdwErrCode ); } } return(dwStatus); } //---------------------------------------------------------------------------- DWORD WINAPI TLSUpgradeLicense( TLS_HANDLE hHandle, LICENSEREQUEST *pRequest, CHALLENGE_CONTEXT ChallengeContext, DWORD cbChallengeResponse, PBYTE pbChallengeResponse, DWORD cbOldLicense, PBYTE pbOldLicense, PDWORD pcbNewLicense, PBYTE* ppbNewLicense, PDWORD pdwErrCode ) /*++ ++*/ { TLSLICENSEREQUEST rpcRequest; RequestToTlsRequest( pRequest, &rpcRequest ); return TLSRpcUpgradeLicense( hHandle, &rpcRequest, ChallengeContext, cbChallengeResponse, pbChallengeResponse, cbOldLicense, pbOldLicense, pcbNewLicense, ppbNewLicense, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSUpgradeLicenseEx( TLS_HANDLE hHandle, PDWORD pSupportFlags, LICENSEREQUEST *pRequest, CHALLENGE_CONTEXT ChallengeContext, DWORD cbChallengeResponse, PBYTE pbChallengeResponse, DWORD cbOldLicense, PBYTE pbOldLicense, DWORD dwQuantity, PDWORD pcbNewLicense, PBYTE* ppbNewLicense, PDWORD pdwErrCode ) /*++ ++*/ { DWORD dwStatus; TLSLICENSEREQUEST rpcRequest; RequestToTlsRequest( pRequest, &rpcRequest ); dwStatus = TLSRpcUpgradeLicenseEx( hHandle, pSupportFlags, &rpcRequest, ChallengeContext, cbChallengeResponse, pbChallengeResponse, cbOldLicense, pbOldLicense, dwQuantity, pcbNewLicense, ppbNewLicense, pdwErrCode ); if (dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE) { *pSupportFlags = 0; dwStatus = TLSRpcUpgradeLicense( hHandle, &rpcRequest, ChallengeContext, cbChallengeResponse, pbChallengeResponse, cbOldLicense, pbOldLicense, pcbNewLicense, ppbNewLicense, pdwErrCode ); } return(dwStatus); } //---------------------------------------------------------------------------- DWORD WINAPI TLSAllocateConcurrentLicense( TLS_HANDLE hHandle, LPTSTR szHydraServer, LICENSEREQUEST *pRequest, LONG *dwQuantity, PDWORD pdwErrCode ) /*++ ++*/ { TLSLICENSEREQUEST rpcRequest; RequestToTlsRequest( pRequest, &rpcRequest ); return TLSRpcAllocateConcurrentLicense( hHandle, szHydraServer, &rpcRequest, dwQuantity, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetLastError( TLS_HANDLE hHandle, DWORD cbBufferSize, LPTSTR pszBuffer, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcGetLastError( hHandle, &cbBufferSize, pszBuffer, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetLastErrorFixed( TLS_HANDLE hHandle, LPTSTR *pszBuffer, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcGetLastErrorFixed( hHandle, pszBuffer, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSKeyPackEnumBegin( TLS_HANDLE hHandle, DWORD dwSearchParm, BOOL bMatchAll, LPLSKeyPackSearchParm lpSearchParm, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcKeyPackEnumBegin( hHandle, dwSearchParm, bMatchAll, lpSearchParm, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSKeyPackEnumNext( TLS_HANDLE hHandle, LPLSKeyPack lpKeyPack, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcKeyPackEnumNext( hHandle, lpKeyPack, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSKeyPackEnumEnd( TLS_HANDLE hHandle, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcKeyPackEnumEnd(hHandle, pdwErrCode); } //---------------------------------------------------------------------------- DWORD WINAPI TLSLicenseEnumBegin( TLS_HANDLE hHandle, DWORD dwSearchParm, BOOL bMatchAll, LPLSLicenseSearchParm lpSearchParm, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcLicenseEnumBegin( hHandle, dwSearchParm, bMatchAll, lpSearchParm, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSLicenseEnumNext( TLS_HANDLE hHandle, LPLSLicense lpLicense, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcLicenseEnumNext( hHandle, lpLicense, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSLicenseEnumNextEx( TLS_HANDLE hHandle, LPLSLicenseEx lpLicenseEx, PDWORD pdwErrCode ) /*++ ++*/ { DWORD dwRet; if (NULL == lpLicenseEx) { return ERROR_INVALID_PARAMETER; } dwRet = TLSRpcLicenseEnumNextEx( hHandle, lpLicenseEx, pdwErrCode ); if (RPC_S_PROCNUM_OUT_OF_RANGE == dwRet) { LSLicense License; dwRet = TLSRpcLicenseEnumNext( hHandle, &License, pdwErrCode ); if ((dwRet == RPC_S_OK) && (NULL != pdwErrCode) && (*pdwErrCode == ERROR_SUCCESS)) { // older versions only support quantity == 1 memcpy(lpLicenseEx,&License,sizeof(License)); lpLicenseEx->dwQuantity = 1; } } return dwRet; } //---------------------------------------------------------------------------- DWORD WINAPI TLSLicenseEnumEnd( TLS_HANDLE hHandle, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcLicenseEnumEnd(hHandle, pdwErrCode); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetAvailableLicenses( TLS_HANDLE hHandle, DWORD dwSearchParm, LPLSKeyPack lplsKeyPack, LPDWORD lpdwAvail, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcGetAvailableLicenses( hHandle, dwSearchParm, lplsKeyPack, lpdwAvail, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetRevokeKeyPackList( TLS_HANDLE hHandle, PDWORD pcbNumberOfRange, LPLSRange *ppRevokeRange, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcGetRevokeKeyPackList( hHandle, pcbNumberOfRange, ppRevokeRange, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetRevokeLicenseList( TLS_HANDLE hHandle, PDWORD pcbNumberOfRange, LPLSRange *ppRevokeRange, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcGetRevokeLicenseList( hHandle, pcbNumberOfRange, ppRevokeRange, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSMarkLicense( TLS_HANDLE hHandle, UCHAR ucFlags, DWORD cbLicense, PBYTE pLicense, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcMarkLicense( hHandle, ucFlags, cbLicense, pLicense, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSCheckLicenseMark( TLS_HANDLE hHandle, DWORD cbLicense, PBYTE pLicense, PUCHAR pucFlags, PDWORD pdwErrCode ) /*++ ++*/ { return TLSRpcCheckLicenseMark( hHandle, cbLicense, pLicense, pucFlags, pdwErrCode ); } //---------------------------------------------------------------------------- DWORD WINAPI TLSGetSupportFlags( TLS_HANDLE hHandle, DWORD *pdwSupportFlags ) /*++ ++*/ { return TLSRpcGetSupportFlags( hHandle, pdwSupportFlags ); }