Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3318 lines
78 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-1998
  5. //
  6. // File: tlsapi.cpp
  7. //
  8. // Contents:
  9. //
  10. // History: 12-09-97 HueiWang Created
  11. //
  12. //---------------------------------------------------------------------------
  13. #include <windows.h>
  14. #include <wincrypt.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <tchar.h>
  18. #include <rpc.h>
  19. #include <ntsecapi.h>
  20. #include <lmcons.h>
  21. #include <lmserver.h>
  22. #include <lmerr.h>
  23. #include <lmapibuf.h>
  24. #include <ntdsapi.h>
  25. #include <dsrole.h>
  26. #include <lmjoin.h>
  27. #include <winldap.h>
  28. #include <winsock2.h>
  29. #include <dsgetdc.h>
  30. #include "lscommon.h"
  31. #include "tlsrpc.h"
  32. #include "tlsapi.h"
  33. #include "tlsapip.h"
  34. #include "secstore.h"
  35. #include "lscsp.h"
  36. #include "license.h"
  37. extern "C" DWORD WINAPI
  38. TLSConnect(
  39. handle_t binding,
  40. TLS_HANDLE *pphContext
  41. );
  42. extern "C" DWORD WINAPI
  43. TLSDisconnect(
  44. TLS_HANDLE* pphContext
  45. );
  46. #include <lmcons.h> // Netxxx API includes
  47. #include <lmserver.h>
  48. #include <lmerr.h>
  49. #include <lmapibuf.h>
  50. #define DISCOVERY_INTERVAL (60 * 60 * 1000)
  51. static HANDLE g_hCachingThreadExit = NULL;
  52. static HANDLE g_hImmediateDiscovery = NULL;
  53. static HANDLE g_hDiscoverySoon = NULL;
  54. static BOOL g_fOffSiteLicenseServer = FALSE;
  55. #define REG_DOMAIN_SERVER_MULTI L"DomainLicenseServerMulti"
  56. #define TERMINAL_SERVICE_PARAM_DISCOVERY "SYSTEM\\CurrentControlSet\\Services\\TermService\\Parameters\\LicenseServers"
  57. // 2 second timeout
  58. #define SERVER_NP_TIMEOUT (2 * 1000)
  59. #define INSTALL_CERT_DELAY (5 * 1000)
  60. BOOL g_fInDomain = -1;
  61. LONG lLibUsage = 0;
  62. typedef struct {
  63. TLS_HANDLE *hBinding;
  64. DWORD dwTimeout; // In milliseconds - INFINITE for none
  65. LARGE_INTEGER timeInitial; // As returned by QueryPerformanceCounter
  66. } LS_ENUM_PARAM, *PLS_ENUM_PARAM;
  67. void * MIDL_user_allocate(size_t size)
  68. {
  69. return(HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, size));
  70. }
  71. void MIDL_user_free( void *pointer)
  72. {
  73. HeapFree(GetProcessHeap(), 0, pointer);
  74. }
  75. #ifdef PRIVATEDEBUG
  76. //
  77. // FUNCTIONS: StartTime()
  78. // EndTime()
  79. //
  80. // USAGE:
  81. // StartTime();
  82. // // Do some work.
  83. // mseconds = EndTime();
  84. //
  85. // RETURN VALUE:
  86. // Milliseconds between StartTime() and EndTime() calls.
  87. LARGE_INTEGER TimeT;
  88. void StartTimeT(void)
  89. {
  90. QueryPerformanceCounter(&TimeT);
  91. }
  92. ULONG EndTimeT()
  93. {
  94. LARGE_INTEGER liDiff;
  95. LARGE_INTEGER liFreq;
  96. QueryPerformanceCounter(&liDiff);
  97. liDiff.QuadPart -= TimeT.QuadPart;
  98. liDiff.QuadPart *= 1000; // Adjust to milliseconds, shouldn't overflow...
  99. (void)QueryPerformanceFrequency(&liFreq);
  100. return ((ULONG)(liDiff.QuadPart / liFreq.QuadPart));
  101. }
  102. #endif
  103. //+------------------------------------------------------------------------
  104. // Function: ConnectToLsServer()
  105. //
  106. // Description:
  107. //
  108. // Binding to sepecific hydra license server
  109. //
  110. // Arguments:
  111. //
  112. // szLsServer - Hydra License Server name
  113. //
  114. // Return Value:
  115. //
  116. // RPC binding handle or NULL if error, use GetLastError() to retrieve
  117. // error.
  118. //-------------------------------------------------------------------------
  119. static TLS_HANDLE WINAPI
  120. ConnectLsServer(
  121. LPTSTR szLsServer,
  122. LPTSTR szProtocol,
  123. LPTSTR szEndPoint,
  124. DWORD dwAuthLevel )
  125. {
  126. LPTSTR szBindingString;
  127. RPC_BINDING_HANDLE hBinding=NULL;
  128. RPC_STATUS status;
  129. TLS_HANDLE pContext=NULL;
  130. BOOL fSuccess;
  131. #ifdef PRIVATEDEBUG
  132. if (NULL != szLsServer)
  133. wprintf(L"server=%s\n",szLsServer);
  134. #endif
  135. //
  136. // If this isn't local
  137. //
  138. if ((NULL != szLsServer) && (NULL != szEndPoint))
  139. {
  140. TCHAR szPipeName[MAX_PATH+1];
  141. if (lstrlen(szLsServer) > ((sizeof(szPipeName) / sizeof(TCHAR)) - 26))
  142. {
  143. #ifdef PRIVATEDEBUG
  144. wprintf(L"Server name too long\n");
  145. #endif
  146. return NULL;
  147. }
  148. //
  149. // First check if license server named pipe exists
  150. //
  151. wsprintf(szPipeName,TEXT("\\\\%s\\pipe\\%s"),szLsServer,TEXT(SZSERVICENAME));
  152. #ifdef PRIVATEDEBUG
  153. StartTimeT();
  154. #endif
  155. fSuccess = WaitNamedPipe(szPipeName,SERVER_NP_TIMEOUT);
  156. #ifdef PRIVATEDEBUG
  157. ULONG ulTime = EndTimeT();
  158. wprintf(L"WaitNamedPipe time == %lu\n",ulTime);
  159. #endif
  160. if (!fSuccess)
  161. {
  162. #ifdef PRIVATEDEBUG
  163. wprintf(L"WaitNamedPipe (%s) failed 0x%x\n",szPipeName,GetLastError());
  164. #endif
  165. return NULL;
  166. }
  167. }
  168. #ifdef PRIVATEDEBUG
  169. else
  170. wprintf(L"Not trying WaitNamedPipe\n");
  171. #endif
  172. status = RpcStringBindingCompose(0,
  173. szProtocol,
  174. szLsServer,
  175. szEndPoint,
  176. 0,
  177. &szBindingString);
  178. if(status!=RPC_S_OK)
  179. {
  180. #ifdef PRIVATEDEBUG
  181. wprintf(L"RpcStringBindingCompose failed 0x%x\n",status);
  182. #endif
  183. return NULL;
  184. }
  185. status=RpcBindingFromStringBinding( szBindingString, &hBinding);
  186. RpcStringFree( &szBindingString );
  187. if(status != RPC_S_OK)
  188. {
  189. #ifdef PRIVATEDEBUG
  190. wprintf(L"RpcBindingFromStringBinding failed 0x%x\n",status);
  191. #endif
  192. return NULL;
  193. }
  194. status = RpcMgmtSetComTimeout(hBinding,RPC_C_BINDING_MIN_TIMEOUT);
  195. if (status != RPC_S_OK)
  196. {
  197. #ifdef PRIVATEDEBUG
  198. wprintf(L"RpcMgmtSetComTimeout failed 0x%x\n",status);
  199. #endif
  200. return NULL;
  201. }
  202. status=RpcBindingSetAuthInfo(hBinding,
  203. 0,
  204. dwAuthLevel,
  205. RPC_C_AUTHN_WINNT,
  206. 0,
  207. 0);
  208. if(status == RPC_S_OK)
  209. {
  210. // Obtain context handle from server
  211. status = TLSConnect( hBinding, &pContext );
  212. if(status != ERROR_SUCCESS)
  213. {
  214. pContext = NULL;
  215. }
  216. }
  217. //
  218. // Memory leak
  219. //
  220. if(hBinding != NULL)
  221. {
  222. RpcBindingFree(&hBinding);
  223. }
  224. SetLastError((status == RPC_S_OK) ? ERROR_SUCCESS : status);
  225. return pContext;
  226. }
  227. //+------------------------------------------------------------------------
  228. //-------------------------------------------------------------------------
  229. DWORD WINAPI
  230. TLSIsLicenseServer(
  231. LPWSTR szServerName
  232. )
  233. /*++
  234. ++*/
  235. {
  236. DWORD dwStatus=ERROR_SUCCESS;
  237. NET_API_STATUS dwNetApiStatus;
  238. LPSERVER_INFO_101 lpServerInfo101=NULL;
  239. SC_HANDLE schService=NULL;
  240. SC_HANDLE schSCManager=NULL;
  241. SERVICE_STATUS ServiceStatus;
  242. TLS_HANDLE pContextHandle=NULL;
  243. //
  244. // verify system is NTS
  245. //
  246. dwNetApiStatus=NetServerGetInfo(szServerName, 101, (LPBYTE*)&lpServerInfo101);
  247. if(dwNetApiStatus != NERR_Success)
  248. return dwNetApiStatus;
  249. do {
  250. //
  251. // Do we check version like 3.51??
  252. //
  253. if((lpServerInfo101->sv101_version_major & MAJOR_VERSION_MASK) < 4)
  254. {
  255. dwStatus = LSERVER_E_INVALID_NT_VERSION;
  256. break;
  257. }
  258. //
  259. // Verify it is NT Server
  260. //
  261. if(!(lpServerInfo101->sv101_type & SV_TYPE_SERVER_NT))
  262. {
  263. dwStatus = LSERVER_E_NOT_NTSERVER;
  264. break;
  265. }
  266. //
  267. // Verify License Server is installed on machine
  268. //
  269. schSCManager = OpenSCManager(szServerName, NULL, SC_MANAGER_ALL_ACCESS);
  270. if(!schSCManager)
  271. {
  272. // Error return :
  273. //
  274. // ERROR_ACCESS_DENIED
  275. // ERROR_DATABASE_DOES_NOT_EXIST
  276. // ERROR_INVALID_PARAMETER
  277. dwStatus = GetLastError();
  278. break;
  279. }
  280. //
  281. // open CertSrv service
  282. // SZSERVICENAME defined in lscommon.h
  283. //
  284. schService = OpenService( schSCManager, _TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS );
  285. if(!schService)
  286. {
  287. // Error return :
  288. //
  289. // ERROR_ACCESS_DENIED
  290. // ERROR_INVALID_HANDLE
  291. // ERROR_INVALID_NAME
  292. // ERROR_SERVICE_DOES_NOT_EXIST
  293. dwStatus = GetLastError();
  294. //
  295. // Simple checking on ERROR_SERVICE_DOES_NOT_EXIST is enough
  296. // without mapping error code.
  297. //
  298. if(dwStatus == ERROR_SERVICE_DOES_NOT_EXIST)
  299. dwStatus = LSERVER_E_LS_NOTPRESENT;
  300. break;
  301. }
  302. //
  303. // Query License Service Status and make sure it is running
  304. //
  305. if(!QueryServiceStatus( schService, &ServiceStatus ))
  306. {
  307. // Error Return:
  308. // ERROR_ACCESS_DENIED
  309. // ERROR_INVALID_HANDLE
  310. dwStatus = GetLastError();
  311. break;
  312. }
  313. if(ServiceStatus.dwCurrentState != SERVICE_RUNNING)
  314. {
  315. dwStatus = LSERVER_E_LS_NOTRUNNING;
  316. break;
  317. }
  318. //
  319. // Should we make an RPC call to detemine if it is busy?
  320. //
  321. // Watch out for ANSI here...
  322. pContextHandle=TLSConnectToLsServer( szServerName );
  323. if(!pContextHandle)
  324. {
  325. dwStatus = GetLastError();
  326. }
  327. } while(FALSE);
  328. if(pContextHandle)
  329. TLSDisconnect(&pContextHandle);
  330. if(schService)
  331. CloseServiceHandle(schService);
  332. if(schSCManager)
  333. CloseServiceHandle(schSCManager);
  334. if(lpServerInfo101)
  335. NetApiBufferFree(lpServerInfo101);
  336. return dwStatus;
  337. }
  338. //+------------------------------------------------------------------------
  339. // Function: BindAnyServer()
  340. //
  341. // Description:
  342. //
  343. // Call back routine for TLSConnectToAnyLsServer()
  344. //
  345. // Arguments:
  346. //
  347. // See EnumerateTlsServer()
  348. //
  349. // Return Value:
  350. //
  351. // Always TRUE to terminate server enumeration
  352. //-------------------------------------------------------------------------
  353. static BOOL
  354. BindAnyServer(
  355. TLS_HANDLE hRpcBinding,
  356. LPCTSTR pszServerName,
  357. HANDLE dwUserData
  358. )
  359. /*++
  360. ++*/
  361. {
  362. PLS_ENUM_PARAM pParam = (PLS_ENUM_PARAM) dwUserData;
  363. TLS_HANDLE* hBinding = pParam->hBinding;
  364. RPC_STATUS rpcStatus;
  365. HKEY hKey = NULL;
  366. DWORD dwBuffer = 0;
  367. DWORD cbBuffer = sizeof (DWORD);
  368. DWORD dwErrCode = 0;
  369. // Skip Windows 2000 License servers
  370. if (hRpcBinding != NULL)
  371. {
  372. DWORD dwSupportFlags = 0;
  373. dwErrCode = TLSGetSupportFlags(
  374. hRpcBinding,
  375. &dwSupportFlags
  376. );
  377. if ((dwErrCode == RPC_S_OK) && !(dwSupportFlags & SUPPORT_WHISTLER_CAL))
  378. {
  379. return FALSE;
  380. }
  381. // If the call fails => Windows 2000 LS
  382. else if(dwErrCode != RPC_S_OK)
  383. {
  384. return FALSE;
  385. }
  386. *hBinding=hRpcBinding;
  387. return TRUE;
  388. }
  389. if (pParam->dwTimeout != INFINITE)
  390. {
  391. LARGE_INTEGER timeDiff;
  392. LARGE_INTEGER timeFreq;
  393. *hBinding=hRpcBinding;
  394. QueryPerformanceCounter(&timeDiff);
  395. timeDiff.QuadPart -= pParam->timeInitial.QuadPart;
  396. timeDiff.QuadPart *= 1000; // Adjust to milliseconds, shouldn't overflow
  397. (void)QueryPerformanceFrequency(&timeFreq);
  398. if (((ULONG)(timeDiff.QuadPart / timeFreq.QuadPart)) > pParam->dwTimeout)
  399. {
  400. #ifdef PRIVATEDEBUG
  401. wprintf(L"BindAnyServer timed out\n");
  402. #endif
  403. return TRUE;
  404. }
  405. }
  406. return FALSE;
  407. }
  408. void
  409. RandomizeArray(LPWSTR *rgwszServers, DWORD cServers)
  410. {
  411. DWORD i;
  412. LPWSTR wszServerTmp;
  413. int val;
  414. if (cServers < 2)
  415. return;
  416. srand(GetTickCount());
  417. for (i = 0; i < cServers; i++)
  418. {
  419. val = rand() % (cServers - i);
  420. if (val == 0)
  421. continue;
  422. //
  423. // Swap # i with # (val+i)
  424. //
  425. wszServerTmp = rgwszServers[i];
  426. rgwszServers[i] = rgwszServers[val+i];
  427. rgwszServers[val+i] = wszServerTmp;
  428. }
  429. }
  430. HRESULT
  431. GetLicenseServersFromReg(LPWSTR wszRegKey, LPWSTR *ppwszServerNames,DWORD *pcServers, LPWSTR **prgwszServers)
  432. {
  433. HRESULT hr = S_OK;
  434. HKEY hKey = NULL;
  435. DWORD dwType;
  436. DWORD cbData = 0;
  437. LPWSTR szServers=NULL, pchServer;
  438. DWORD dwErr;
  439. DWORD i,val;
  440. DWORD iLocalComputer = (DWORD)(-1);
  441. WCHAR szLocalComputerName[MAXCOMPUTERNAMELENGTH+1] = L"";
  442. DWORD cbLocalComputerName=MAXCOMPUTERNAMELENGTH+1;
  443. *ppwszServerNames = NULL;
  444. *prgwszServers = NULL;
  445. dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  446. TEXT(LSERVER_DISCOVERY_PARAMETER_KEY),
  447. 0,
  448. KEY_READ,
  449. &hKey);
  450. if (dwErr != ERROR_SUCCESS)
  451. {
  452. hr = HRESULT_FROM_WIN32(dwErr);
  453. goto CleanErr;
  454. }
  455. dwErr = RegQueryValueEx(hKey,
  456. wszRegKey,
  457. NULL,
  458. &dwType,
  459. NULL,
  460. &cbData);
  461. if (dwErr != ERROR_SUCCESS)
  462. {
  463. hr = HRESULT_FROM_WIN32(dwErr);
  464. goto CleanErr;
  465. }
  466. if ((dwType != REG_MULTI_SZ) || (cbData < (2 * sizeof(WCHAR))))
  467. {
  468. hr = E_FAIL;
  469. goto CleanErr;
  470. }
  471. szServers = (LPWSTR) LocalAlloc(LPTR,cbData);
  472. if (NULL == szServers)
  473. {
  474. hr = E_OUTOFMEMORY;
  475. goto CleanErr;
  476. }
  477. dwErr = RegQueryValueEx(hKey,
  478. wszRegKey,
  479. NULL,
  480. &dwType,
  481. (PBYTE)szServers,
  482. &cbData);
  483. if (dwErr != ERROR_SUCCESS)
  484. {
  485. hr = HRESULT_FROM_WIN32(dwErr);
  486. goto CleanErr;
  487. }
  488. for (i = 0, pchServer = szServers; (pchServer != NULL) && (*pchServer != L'\0'); pchServer = wcschr(pchServer,L'\0')+1, i++)
  489. ;
  490. if (i == 0)
  491. {
  492. hr = E_FAIL;
  493. goto CleanErr;
  494. }
  495. *pcServers = i;
  496. *prgwszServers = (LPWSTR *)LocalAlloc(LPTR,sizeof(LPWSTR) * (*pcServers));
  497. if (*prgwszServers == NULL)
  498. {
  499. hr = E_OUTOFMEMORY;
  500. goto CleanErr;
  501. }
  502. // Don't treat error from this function as fatal
  503. GetComputerName(szLocalComputerName, &cbLocalComputerName);
  504. for (i = 0, pchServer = szServers; (i < (*pcServers)) && (pchServer != NULL) && (*pchServer != L'\0'); pchServer = wcschr(pchServer,L'\0')+1, i++) {
  505. (*prgwszServers)[i] = pchServer;
  506. if ((iLocalComputer == (DWORD)(-1)) && (wcscmp(pchServer,szLocalComputerName) == 0))
  507. {
  508. iLocalComputer = i;
  509. }
  510. }
  511. //
  512. // Put local computer at head of list
  513. //
  514. if (iLocalComputer != (DWORD)(-1))
  515. {
  516. if (iLocalComputer != 0)
  517. {
  518. //
  519. // Swap # iLocalComputer with # 0
  520. //
  521. pchServer = (*prgwszServers)[iLocalComputer];
  522. (*prgwszServers)[iLocalComputer] = (*prgwszServers)[0];
  523. (*prgwszServers)[0] = pchServer;
  524. }
  525. RandomizeArray((*prgwszServers)+1,(*pcServers) - 1);
  526. }
  527. else
  528. {
  529. RandomizeArray((*prgwszServers),*pcServers);
  530. }
  531. *ppwszServerNames = szServers;
  532. CleanErr:
  533. if (FAILED(hr))
  534. {
  535. if (NULL != szServers)
  536. {
  537. LocalFree(szServers);
  538. }
  539. if (NULL != *prgwszServers)
  540. {
  541. LocalFree(*prgwszServers);
  542. }
  543. }
  544. if (hKey != NULL)
  545. {
  546. RegCloseKey(hKey);
  547. }
  548. return hr;
  549. }
  550. HRESULT
  551. WriteLicenseServersToReg(LPWSTR wszRegKey, LPWSTR pwszServerNames,DWORD cchServers)
  552. {
  553. HRESULT hr;
  554. HKEY hKey = NULL;
  555. DWORD dwType = REG_MULTI_SZ;
  556. DWORD dwErr;
  557. DWORD dwDisp;
  558. if ((pwszServerNames == NULL) || (cchServers < 2))
  559. {
  560. //
  561. // Delete the value
  562. //
  563. dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  564. TEXT(LSERVER_DISCOVERY_PARAMETER_KEY),
  565. 0,
  566. KEY_WRITE,
  567. &hKey);
  568. if (dwErr != ERROR_SUCCESS)
  569. {
  570. hr = HRESULT_FROM_WIN32(dwErr);
  571. goto CleanErr;
  572. }
  573. dwErr = RegDeleteValue(hKey,wszRegKey);
  574. if (dwErr != ERROR_SUCCESS)
  575. {
  576. hr = HRESULT_FROM_WIN32(dwErr);
  577. goto CleanErr;
  578. }
  579. hr = S_OK;
  580. goto CleanErr;
  581. }
  582. dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  583. TEXT(LSERVER_DISCOVERY_PARAMETER_KEY),
  584. 0,
  585. TEXT(""),
  586. REG_OPTION_NON_VOLATILE,
  587. KEY_WRITE,
  588. NULL,
  589. &hKey,
  590. &dwDisp);
  591. if (dwErr != ERROR_SUCCESS)
  592. {
  593. hr = HRESULT_FROM_WIN32(dwErr);
  594. goto CleanErr;
  595. }
  596. dwErr = RegSetValueEx(hKey,
  597. wszRegKey,
  598. 0,
  599. dwType,
  600. (CONST BYTE *)pwszServerNames,
  601. cchServers*sizeof(WCHAR));
  602. if (dwErr != ERROR_SUCCESS)
  603. {
  604. hr = HRESULT_FROM_WIN32(dwErr);
  605. goto CleanErr;
  606. }
  607. CleanErr:
  608. if (hKey != NULL)
  609. {
  610. RegCloseKey(hKey);
  611. }
  612. return hr;
  613. }
  614. //
  615. // Free pszDomain using NetApiBufferFree
  616. //
  617. DWORD WINAPI
  618. TLSInDomain(BOOL *pfInDomain, LPWSTR *pszDomain)
  619. {
  620. NET_API_STATUS dwErr;
  621. DSROLE_PRIMARY_DOMAIN_INFO_BASIC *pDomainInfo = NULL;
  622. PDOMAIN_CONTROLLER_INFO pdcInfo = NULL;
  623. if (pfInDomain == NULL)
  624. {
  625. return ERROR_INVALID_PARAMETER;
  626. }
  627. *pfInDomain = FALSE;
  628. //
  629. // Check if we're in a workgroup
  630. //
  631. dwErr = DsRoleGetPrimaryDomainInformation(NULL,
  632. DsRolePrimaryDomainInfoBasic,
  633. (PBYTE *) &pDomainInfo);
  634. if ((dwErr != NO_ERROR) || (pDomainInfo == NULL))
  635. {
  636. return dwErr;
  637. }
  638. switch (pDomainInfo->MachineRole)
  639. {
  640. case DsRole_RoleStandaloneWorkstation:
  641. case DsRole_RoleStandaloneServer:
  642. DsRoleFreeMemory(pDomainInfo);
  643. if (NULL != pszDomain)
  644. {
  645. NETSETUP_JOIN_STATUS BufferType;
  646. dwErr = NetGetJoinInformation(NULL,pszDomain,&BufferType);
  647. }
  648. return dwErr;
  649. break; // just in case
  650. }
  651. DsRoleFreeMemory(pDomainInfo);
  652. dwErr = DsGetDcName(NULL, // Computer Name
  653. NULL, // Domain Name
  654. NULL, // Domain GUID
  655. NULL, // Site Name
  656. DS_DIRECTORY_SERVICE_PREFERRED,
  657. &pdcInfo);
  658. if ((dwErr != NO_ERROR) || (pdcInfo == NULL))
  659. {
  660. if (dwErr == ERROR_NO_SUCH_DOMAIN)
  661. {
  662. *pfInDomain = FALSE;
  663. return NO_ERROR;
  664. }
  665. else
  666. {
  667. if (pdcInfo == NULL)
  668. dwErr = ERROR_INTERNAL_ERROR;
  669. return dwErr;
  670. }
  671. }
  672. if (pdcInfo->Flags & DS_DS_FLAG)
  673. {
  674. *pfInDomain = TRUE;
  675. }
  676. if (pszDomain != NULL)
  677. {
  678. dwErr = NetApiBufferAllocate((wcslen(pdcInfo->DomainName)+1) * sizeof(WCHAR),
  679. (LPVOID *)pszDomain);
  680. if ((NERR_Success == dwErr) && (NULL != *pszDomain))
  681. {
  682. wcscpy(*pszDomain,pdcInfo->DomainName);
  683. }
  684. }
  685. if (pdcInfo != NULL)
  686. NetApiBufferFree(pdcInfo);
  687. return dwErr;
  688. }
  689. /*++
  690. Function:
  691. LicenseServerCachingThread
  692. Description:
  693. This is the thread that does the license server caching.
  694. Arguments:
  695. lpParam - contains the exit event handle
  696. Returns:
  697. Always 1
  698. --*/
  699. DWORD WINAPI
  700. LicenseServerCachingThread(
  701. LPVOID lpParam )
  702. {
  703. DWORD
  704. dwWaitStatus;
  705. HANDLE
  706. hExit = (HANDLE)lpParam;
  707. DWORD
  708. dwDiscoveryInterval = DISCOVERY_INTERVAL;
  709. HANDLE
  710. rgWaitHandles[] = {hExit,g_hImmediateDiscovery,g_hDiscoverySoon};
  711. BOOL
  712. bFoundServer;
  713. BOOL
  714. bSkipOne = FALSE;
  715. //
  716. // Yield our time slice to other threads now, so that the terminal server
  717. // service can start up quickly. Refresh the license server cache when we
  718. // resume our time slice.
  719. //
  720. Sleep( 0 );
  721. while (1)
  722. {
  723. if (!bSkipOne)
  724. {
  725. bFoundServer = TLSRefreshLicenseServerCache(INFINITE);
  726. if ((!g_fOffSiteLicenseServer) && bFoundServer)
  727. {
  728. dwDiscoveryInterval = INFINITE;
  729. }
  730. }
  731. else
  732. {
  733. bSkipOne = FALSE;
  734. }
  735. dwWaitStatus = WaitForMultipleObjects(
  736. sizeof(rgWaitHandles) / sizeof(HANDLE),
  737. rgWaitHandles,
  738. FALSE, // wait for any one event
  739. dwDiscoveryInterval);
  740. if (WAIT_OBJECT_0 == dwWaitStatus)
  741. {
  742. // hExit was signalled
  743. goto done;
  744. }
  745. if ((WAIT_OBJECT_0+1) == dwWaitStatus)
  746. {
  747. // g_hImmediateDiscovery was signalled
  748. // reduce dwDiscoveryInterval
  749. dwDiscoveryInterval = DISCOVERY_INTERVAL;
  750. }
  751. if ((WAIT_OBJECT_0+2) == dwWaitStatus)
  752. {
  753. // g_hDiscoverySoon was signalled
  754. // reduce dwDiscoveryInterval, but wait one round
  755. dwDiscoveryInterval = DISCOVERY_INTERVAL;
  756. bSkipOne = TRUE;
  757. }
  758. // we timed out, or hImmediateDiscovery was signalled. Re-start
  759. // discovery
  760. }
  761. done:
  762. return 1;
  763. }
  764. extern "C" void
  765. TLSShutdown()
  766. {
  767. if (0 < InterlockedDecrement(&lLibUsage))
  768. {
  769. //
  770. // Someone else is using it
  771. //
  772. return;
  773. }
  774. TLSStopDiscovery();
  775. LsCsp_Exit();
  776. }
  777. extern "C" DWORD WINAPI
  778. TLSInit()
  779. {
  780. LICENSE_STATUS status;
  781. if (0 != InterlockedExchangeAdd(&lLibUsage,1))
  782. {
  783. //
  784. // Already been initialized
  785. //
  786. return ERROR_SUCCESS;
  787. }
  788. status = LsCsp_Initialize();
  789. if (LICENSE_STATUS_OK != status)
  790. {
  791. switch (status)
  792. {
  793. case LICENSE_STATUS_OUT_OF_MEMORY:
  794. return ERROR_NOT_ENOUGH_MEMORY;
  795. case LICENSE_STATUS_NO_CERTIFICATE:
  796. return SCARD_E_CERTIFICATE_UNAVAILABLE;
  797. case LICENSE_STATUS_INVALID_CERTIFICATE:
  798. return CERT_E_MALFORMED;
  799. default:
  800. return E_FAIL;
  801. }
  802. }
  803. return ERROR_SUCCESS;
  804. }
  805. extern "C" DWORD WINAPI
  806. TLSStartDiscovery()
  807. {
  808. HANDLE hCachingThread = NULL;
  809. HANDLE hEvent;
  810. if (NULL != g_hCachingThreadExit)
  811. {
  812. // already started
  813. return ERROR_SUCCESS;
  814. }
  815. //
  816. // Create the event to signal thread exit
  817. //
  818. g_hCachingThreadExit = CreateEvent( NULL, FALSE, FALSE, NULL );
  819. if( NULL == g_hCachingThreadExit )
  820. {
  821. return GetLastError();
  822. }
  823. g_hImmediateDiscovery = CreateEvent(NULL,FALSE,FALSE,NULL);
  824. if (NULL == g_hImmediateDiscovery)
  825. {
  826. hEvent = g_hCachingThreadExit;
  827. g_hCachingThreadExit = NULL;
  828. CloseHandle(hEvent);
  829. return GetLastError();
  830. }
  831. g_hDiscoverySoon = CreateEvent(NULL,FALSE,FALSE,NULL);
  832. if (NULL == g_hDiscoverySoon)
  833. {
  834. hEvent = g_hCachingThreadExit;
  835. g_hCachingThreadExit = NULL;
  836. CloseHandle(hEvent);
  837. hEvent = g_hImmediateDiscovery;
  838. g_hImmediateDiscovery = NULL;
  839. CloseHandle(hEvent);
  840. return GetLastError();
  841. }
  842. //
  843. // Create the caching thread
  844. //
  845. hCachingThread = CreateThread(
  846. NULL,
  847. 0,
  848. LicenseServerCachingThread,
  849. ( LPVOID )g_hCachingThreadExit,
  850. 0,
  851. NULL );
  852. if (hCachingThread == NULL)
  853. {
  854. hEvent = g_hCachingThreadExit;
  855. g_hCachingThreadExit = NULL;
  856. CloseHandle(hEvent);
  857. hEvent = g_hImmediateDiscovery;
  858. g_hImmediateDiscovery = NULL;
  859. CloseHandle(hEvent);
  860. hEvent = g_hDiscoverySoon;
  861. g_hDiscoverySoon = NULL;
  862. CloseHandle(hEvent);
  863. return GetLastError();
  864. }
  865. CloseHandle(hCachingThread);
  866. return ERROR_SUCCESS;
  867. }
  868. extern "C" DWORD WINAPI
  869. TLSStopDiscovery()
  870. {
  871. HANDLE hEvent;
  872. //
  873. // Signal the thread to exit
  874. //
  875. if (NULL != g_hCachingThreadExit)
  876. {
  877. SetEvent( g_hCachingThreadExit );
  878. hEvent = g_hCachingThreadExit;
  879. g_hCachingThreadExit = NULL;
  880. CloseHandle(hEvent);
  881. hEvent = g_hImmediateDiscovery;
  882. g_hImmediateDiscovery = NULL;
  883. CloseHandle(hEvent);
  884. hEvent = g_hDiscoverySoon;
  885. g_hDiscoverySoon = NULL;
  886. CloseHandle(hEvent);
  887. }
  888. return ERROR_SUCCESS;
  889. }
  890. //
  891. // Number of DCs to allocate space for at a time
  892. //
  893. #define DC_LIST_CHUNK 10
  894. //+------------------------------------------------------------------------
  895. // Function:
  896. //
  897. // EnumerateLsServer()
  898. //
  899. // Description:
  900. //
  901. // Routine to enumerate all hydra license server in network
  902. //
  903. // Arguments:
  904. //
  905. // szScope - Scope limit, NULL if doen't care.
  906. // dwPlatformType - verify if license server have licenses for this platform,
  907. // LSKEYPACKPLATFORMTYPE_UNKNOWN if doesn't care.
  908. // fCallBack - call back routine when EnumerateServer() founds any server,
  909. // dwUserData - data to be pass to call back routine
  910. //
  911. // Return Value:
  912. //
  913. // RPC_S_OK or any RPC specific error code.
  914. //
  915. // NOTE:
  916. //
  917. // Enumeration terminate when either there is no more server or call back
  918. // routine return TRUE.
  919. //
  920. //-------------------------------------------------------------------------
  921. DWORD WINAPI
  922. EnumerateTlsServerInDomain(
  923. IN LPCTSTR szDomain,
  924. IN TLSENUMERATECALLBACK fCallBack,
  925. IN HANDLE dwUserData,
  926. IN DWORD dwTimeOut,
  927. IN BOOL fRegOnly,
  928. IN OUT BOOL *pfOffSite
  929. )
  930. /*++
  931. ++*/
  932. {
  933. DWORD entriesread = 0;
  934. BOOL bCancel=FALSE;
  935. DWORD dwErrCode;
  936. LPWSTR pwszServerTmp = NULL;
  937. LPWSTR pwszServer = NULL;
  938. HRESULT hr;
  939. LPWSTR pwszServers = NULL;
  940. LPWSTR pwszServersTmp = NULL;
  941. DWORD cchServers = 0;
  942. DWORD cchServer;
  943. LPWSTR *rgwszServers = NULL;
  944. LPWSTR *rgwszServersTmp;
  945. LPWSTR pwszServerNames = NULL;
  946. DWORD dwErr = ERROR_SUCCESS, i;
  947. HANDLE hDcOpen = NULL;
  948. LPWSTR szSiteName = NULL;
  949. BOOL fOffSiteIn;
  950. BOOL fFoundOne = FALSE;
  951. BOOL fFoundOneOffSite = FALSE;
  952. DWORD cChunks = 0;
  953. DWORD cServersOnSite = 0;
  954. if (fRegOnly)
  955. {
  956. //
  957. // check for a license server in the registry
  958. //
  959. hr = GetLicenseServersFromReg(REG_DOMAIN_SERVER_MULTI,&pwszServerNames,&entriesread,&rgwszServers);
  960. if (FAILED(hr))
  961. {
  962. dwErr = hr;
  963. goto Cleanup;
  964. }
  965. }
  966. else
  967. {
  968. if (NULL == pfOffSite)
  969. {
  970. return ERROR_INVALID_PARAMETER;
  971. }
  972. fOffSiteIn = *pfOffSite;
  973. *pfOffSite = FALSE;
  974. dwErr = DsGetSiteName(NULL,&szSiteName);
  975. if(dwErr != ERROR_SUCCESS)
  976. {
  977. #ifdef PRIVATEDEBUG
  978. wprintf(L"DsGetSiteName failed %x\n",dwErr);
  979. #endif
  980. goto Cleanup;
  981. }
  982. dwErr = DsGetDcOpenW(szDomain,
  983. fOffSiteIn ? DS_NOTIFY_AFTER_SITE_RECORDS: DS_ONLY_DO_SITE_NAME,
  984. szSiteName,
  985. NULL, // DomainGuid
  986. NULL, // DnsForestName
  987. 0, // Flags
  988. &hDcOpen
  989. );
  990. if(dwErr != ERROR_SUCCESS)
  991. {
  992. #ifdef PRIVATEDEBUG
  993. wprintf(L"DsGetDcOpen failed %x\n",dwErr);
  994. #endif
  995. goto Cleanup;
  996. }
  997. rgwszServers = (LPWSTR *) LocalAlloc(LPTR,
  998. DC_LIST_CHUNK * sizeof(LPWSTR));
  999. if (NULL == rgwszServers)
  1000. {
  1001. #ifdef PRIVATEDEBUG
  1002. wprintf(L"Out of memory\n");
  1003. #endif
  1004. dwErr = E_OUTOFMEMORY;
  1005. goto Cleanup;
  1006. }
  1007. cChunks = 1;
  1008. //
  1009. // Read the whole DC list
  1010. //
  1011. do
  1012. {
  1013. if (entriesread >= (cChunks * DC_LIST_CHUNK))
  1014. {
  1015. cChunks++;
  1016. rgwszServersTmp = (LPWSTR *)
  1017. LocalReAlloc(rgwszServers,
  1018. DC_LIST_CHUNK * sizeof(LPWSTR) * cChunks,
  1019. LHND);
  1020. if (NULL == rgwszServersTmp)
  1021. {
  1022. dwErr = E_OUTOFMEMORY;
  1023. goto Cleanup;
  1024. }
  1025. else
  1026. {
  1027. rgwszServers = rgwszServersTmp;
  1028. }
  1029. }
  1030. dwErr = DsGetDcNextW(hDcOpen,
  1031. NULL,
  1032. NULL,
  1033. rgwszServers+entriesread);
  1034. if (ERROR_FILEMARK_DETECTED == dwErr)
  1035. {
  1036. // Now going off-site; use NULL ptr marker
  1037. rgwszServers[entriesread] = NULL;
  1038. cServersOnSite = entriesread;
  1039. dwErr = ERROR_SUCCESS;
  1040. fFoundOneOffSite = TRUE;
  1041. }
  1042. entriesread++;
  1043. } while (ERROR_SUCCESS == dwErr);
  1044. // don't count the final error
  1045. entriesread--;
  1046. if (!fFoundOneOffSite)
  1047. cServersOnSite = entriesread;
  1048. // Now randomize the two portions of the array
  1049. RandomizeArray(rgwszServers,cServersOnSite);
  1050. if (fFoundOneOffSite)
  1051. {
  1052. RandomizeArray(rgwszServers+cServersOnSite+1,
  1053. entriesread - cServersOnSite - 1);
  1054. }
  1055. // Now allocate memory for registry entry
  1056. pwszServers = (LPWSTR) LocalAlloc(LPTR,2*sizeof(WCHAR));
  1057. if (NULL == pwszServers)
  1058. {
  1059. #ifdef PRIVATEDEBUG
  1060. wprintf(L"Out of memory\n");
  1061. #endif
  1062. dwErr = E_OUTOFMEMORY;
  1063. goto Cleanup;
  1064. }
  1065. cchServers = 2;
  1066. pwszServers[0] = pwszServers[1] = L'\0';
  1067. }
  1068. for(i=0; bCancel == FALSE; i++)
  1069. {
  1070. PCONTEXT_HANDLE pContext=NULL;
  1071. RPC_STATUS rpcStatus;
  1072. if (!fRegOnly)
  1073. {
  1074. if (fFoundOneOffSite && i == cServersOnSite)
  1075. {
  1076. if (fFoundOne)
  1077. break;
  1078. // Now going off-site
  1079. i++;
  1080. *pfOffSite = TRUE;
  1081. }
  1082. }
  1083. if (i >= entriesread)
  1084. break;
  1085. pwszServerTmp = rgwszServers[i];
  1086. bCancel=fCallBack(pContext, pwszServerTmp, dwUserData);
  1087. if(bCancel == TRUE)
  1088. continue;
  1089. if(!(pContext = TLSConnectToLsServer(pwszServerTmp)))
  1090. {
  1091. //
  1092. // could be access denied.
  1093. //
  1094. #ifdef PRIVATEDEBUG
  1095. wprintf(L"Can't connect to %s\n",pwszServerTmp);
  1096. #endif
  1097. continue;
  1098. }
  1099. #ifdef PRIVATEDEBUG
  1100. wprintf(L"!!!Connected to %s\n",pwszServerTmp);
  1101. #endif
  1102. do {
  1103. //
  1104. // Skip enterprise server
  1105. //
  1106. DWORD dwVersion;
  1107. rpcStatus = TLSGetVersion( pContext, &dwVersion );
  1108. if(rpcStatus != RPC_S_OK)
  1109. {
  1110. break;
  1111. }
  1112. #if ENFORCE_LICENSING
  1113. //
  1114. // W2K Beta 3 to RC1 upgrade, don't connect to any non-enforce
  1115. // server 5.2 or older
  1116. //
  1117. if(IS_ENFORCE_LSSERVER(dwVersion) == FALSE)
  1118. {
  1119. if( GET_LSSERVER_MAJOR_VERSION(dwVersion) <= 5 &&
  1120. GET_LSSERVER_MINOR_VERSION(dwVersion) <= 2 )
  1121. {
  1122. #if DBG
  1123. OutputDebugString(pwszServerTmp);
  1124. OutputDebugString(_TEXT(" old License Server\n"));
  1125. #endif
  1126. continue;
  1127. }
  1128. }
  1129. //
  1130. // Prevent beta <-> RTM server talking to each other
  1131. //
  1132. //
  1133. // TLSIsBetaNTServer() returns TRUE if eval NT
  1134. // IS_LSSERVER_RTM() returns TRUE if LS is an RTM.
  1135. //
  1136. if( TLSIsBetaNTServer() == IS_LSSERVER_RTM(dwVersion) )
  1137. {
  1138. continue;
  1139. }
  1140. #endif
  1141. if(dwVersion & TLS_VERSION_ENTERPRISE_BIT)
  1142. {
  1143. continue;
  1144. }
  1145. bCancel=fCallBack(pContext, pwszServerTmp, dwUserData);
  1146. if (!fRegOnly)
  1147. {
  1148. //
  1149. // Add to list of servers
  1150. //
  1151. cchServer = wcslen(pwszServerTmp);
  1152. pwszServersTmp = (LPWSTR) LocalReAlloc(pwszServers,(cchServers+cchServer+1)*sizeof(TCHAR),LHND);
  1153. if (NULL == pwszServersTmp)
  1154. {
  1155. break;
  1156. }
  1157. pwszServers = pwszServersTmp;
  1158. if (cchServers == 2)
  1159. {
  1160. wcscpy(pwszServers,pwszServerTmp);
  1161. cchServers += cchServer;
  1162. } else
  1163. {
  1164. wcscpy(pwszServers+cchServers-1,pwszServerTmp);
  1165. cchServers += cchServer + 1;
  1166. }
  1167. pwszServers[cchServers-1] = L'\0';
  1168. }
  1169. fFoundOne = TRUE;
  1170. } while (FALSE);
  1171. if(bCancel == FALSE && pContext != NULL)
  1172. {
  1173. TLSDisconnect(&pContext);
  1174. }
  1175. } // for loop
  1176. if (!fRegOnly)
  1177. {
  1178. WriteLicenseServersToReg(REG_DOMAIN_SERVER_MULTI,pwszServers,cchServers);
  1179. }
  1180. Cleanup:
  1181. if (NULL != hDcOpen)
  1182. DsGetDcCloseW(hDcOpen);
  1183. if (NULL != rgwszServers)
  1184. {
  1185. if (!fRegOnly)
  1186. {
  1187. for (i = 0; i < entriesread; i++)
  1188. {
  1189. if (NULL != rgwszServers[i])
  1190. {
  1191. NetApiBufferFree(rgwszServers[i]);
  1192. }
  1193. }
  1194. }
  1195. LocalFree(rgwszServers);
  1196. }
  1197. if (szSiteName)
  1198. NetApiBufferFree(szSiteName);
  1199. if (pwszServerNames)
  1200. LocalFree(pwszServerNames);
  1201. if (pwszServers)
  1202. LocalFree(pwszServers);
  1203. if (pwszServer)
  1204. LocalFree(pwszServer);
  1205. return dwErr;
  1206. }
  1207. DWORD WINAPI
  1208. EnumerateTlsServerInWorkGroup(
  1209. IN TLSENUMERATECALLBACK pfCallBack,
  1210. IN HANDLE dwUserData,
  1211. IN DWORD dwTimeOut,
  1212. IN BOOL fRegOnly
  1213. )
  1214. /*++
  1215. ++*/
  1216. {
  1217. DWORD dwStatus=ERROR_SUCCESS;
  1218. TCHAR szServerMailSlotName[MAX_PATH+1];
  1219. TCHAR szLocalMailSlotName[MAX_PATH+1];
  1220. HANDLE hClientSlot = INVALID_HANDLE_VALUE;
  1221. HANDLE hServerSlot = INVALID_HANDLE_VALUE;
  1222. TCHAR szDiscMsg[MAX_MAILSLOT_MSG_SIZE+1];
  1223. TCHAR szComputerName[MAXCOMPUTERNAMELENGTH+1];
  1224. TCHAR szRandomMailSlotName[MAXCOMPUTERNAMELENGTH+1];
  1225. DWORD cbComputerName=MAXCOMPUTERNAMELENGTH+1;
  1226. DWORD cbWritten=0;
  1227. DWORD cbRead=0;
  1228. BOOL bCancel = FALSE;
  1229. DWORD dwErrCode;
  1230. HRESULT hr;
  1231. LPWSTR pwszServers = NULL;
  1232. LPWSTR pwszServersTmp = NULL;
  1233. DWORD cchServers = 0;
  1234. DWORD cchServer;
  1235. LPWSTR *rgwszServers = NULL;
  1236. LPWSTR pwszServerNames = NULL;
  1237. DWORD cServers = 0;
  1238. DWORD i = 0;
  1239. LPWSTR pwszServerTmp = szComputerName;
  1240. if (!fRegOnly)
  1241. {
  1242. if(!GetComputerName(szComputerName, &cbComputerName))
  1243. {
  1244. dwStatus = GetLastError();
  1245. goto cleanup;
  1246. }
  1247. if (0 == (1 & GetSystemMetrics(SM_NETWORK)))
  1248. {
  1249. // No network; try local machine
  1250. #ifdef PRIVATEDEBUG
  1251. wprintf(L"No network, trying local computer=%s\n",szComputerName);
  1252. #endif
  1253. dwStatus = ERROR_SUCCESS;
  1254. goto TryServer;
  1255. }
  1256. wsprintf(
  1257. szRandomMailSlotName,
  1258. _TEXT("%08x"),
  1259. GetCurrentThreadId()
  1260. );
  1261. _stprintf(
  1262. szLocalMailSlotName,
  1263. _TEXT("\\\\.\\mailslot\\%s"),
  1264. szRandomMailSlotName
  1265. );
  1266. //
  1267. // Create local mail slot for server's response
  1268. //
  1269. hClientSlot=CreateMailslot(
  1270. szLocalMailSlotName,
  1271. 0,
  1272. (dwTimeOut == MAILSLOT_WAIT_FOREVER) ? 5 * 1000: dwTimeOut,
  1273. NULL
  1274. );
  1275. if(hClientSlot == INVALID_HANDLE_VALUE)
  1276. {
  1277. dwStatus = GetLastError();
  1278. goto cleanup;
  1279. }
  1280. //
  1281. // Open server's mail slot
  1282. //
  1283. _stprintf(
  1284. szServerMailSlotName,
  1285. _TEXT("\\\\%s\\mailslot\\%s"),
  1286. _TEXT("*"),
  1287. _TEXT(SERVERMAILSLOTNAME)
  1288. );
  1289. hServerSlot=CreateFile(
  1290. szServerMailSlotName,
  1291. GENERIC_WRITE, // only need write
  1292. FILE_SHARE_READ,
  1293. NULL,
  1294. OPEN_EXISTING,
  1295. FILE_ATTRIBUTE_NORMAL,
  1296. NULL
  1297. );
  1298. if(hServerSlot == INVALID_HANDLE_VALUE)
  1299. {
  1300. dwStatus = GetLastError();
  1301. goto cleanup;
  1302. }
  1303. //
  1304. // Formulate discovery message
  1305. //
  1306. _stprintf(
  1307. szDiscMsg,
  1308. _TEXT("%s %c%s%c %c%s%c"),
  1309. _TEXT(LSERVER_DISCOVERY),
  1310. _TEXT(LSERVER_OPEN_BLK),
  1311. szComputerName,
  1312. _TEXT(LSERVER_CLOSE_BLK),
  1313. _TEXT(LSERVER_OPEN_BLK),
  1314. szRandomMailSlotName,
  1315. _TEXT(LSERVER_CLOSE_BLK)
  1316. );
  1317. if (!WriteFile(hServerSlot, szDiscMsg, (_tcslen(szDiscMsg) + 1) * sizeof(TCHAR), &cbWritten, NULL) ||
  1318. (cbWritten != (_tcslen(szDiscMsg) + 1 ) * sizeof(TCHAR)))
  1319. {
  1320. dwStatus = GetLastError();
  1321. if (dwStatus == ERROR_NETWORK_UNREACHABLE)
  1322. {
  1323. // No network; try local machine
  1324. #ifdef PRIVATEDEBUG
  1325. wprintf(L"No network, trying local computer=%s\n",szComputerName);
  1326. #endif
  1327. dwStatus = ERROR_SUCCESS;
  1328. goto TryServer;
  1329. }
  1330. else
  1331. {
  1332. goto cleanup;
  1333. }
  1334. }
  1335. // Allocate for registry entry
  1336. pwszServers = (LPWSTR) LocalAlloc(LPTR,2*sizeof(WCHAR));
  1337. if (NULL == pwszServers)
  1338. {
  1339. #ifdef PRIVATEDEBUG
  1340. wprintf(L"Out of memory\n");
  1341. #endif
  1342. dwStatus = E_OUTOFMEMORY;
  1343. goto cleanup;
  1344. }
  1345. cchServers = 2;
  1346. pwszServers[0] = pwszServers[1] = L'\0';
  1347. } else
  1348. {
  1349. //
  1350. // check for a license server in the registry
  1351. //
  1352. hr = GetLicenseServersFromReg(REG_DOMAIN_SERVER_MULTI,&pwszServerNames,&cServers,&rgwszServers);
  1353. if (FAILED(hr))
  1354. {
  1355. dwStatus = hr;
  1356. goto cleanup;
  1357. }
  1358. }
  1359. do {
  1360. if(fRegOnly)
  1361. {
  1362. if (i >= cServers)
  1363. {
  1364. break;
  1365. }
  1366. pwszServerTmp = rgwszServers[i++];
  1367. } else
  1368. {
  1369. memset(szComputerName, 0, sizeof(szComputerName));
  1370. if(!ReadFile(hClientSlot, szComputerName, sizeof(szComputerName) - sizeof(TCHAR), &cbRead, NULL))
  1371. {
  1372. dwStatus=GetLastError();
  1373. break;
  1374. }
  1375. #ifdef PRIVATEDEBUG
  1376. wprintf(L"Trying server=%s\n",szComputerName);
  1377. #endif
  1378. }
  1379. TryServer:
  1380. bCancel=pfCallBack(NULL, pwszServerTmp, dwUserData);
  1381. if(bCancel == TRUE)
  1382. {
  1383. continue;
  1384. }
  1385. PCONTEXT_HANDLE pContext=NULL;
  1386. RPC_STATUS rpcStatus;
  1387. if(!(pContext = TLSConnectToLsServer(pwszServerTmp)))
  1388. {
  1389. //
  1390. // could be access denied.
  1391. //
  1392. continue;
  1393. }
  1394. do {
  1395. //
  1396. // Skip enterprise server
  1397. //
  1398. DWORD dwVersion;
  1399. rpcStatus = TLSGetVersion( pContext, &dwVersion );
  1400. if(rpcStatus != RPC_S_OK)
  1401. {
  1402. continue;
  1403. }
  1404. #if ENFORCE_LICENSING
  1405. //
  1406. // W2K Beta 3 to RC1 upgrade, don't connect to any non-enforce
  1407. // server 5.2 or older
  1408. //
  1409. if(IS_ENFORCE_LSSERVER(dwVersion) == FALSE)
  1410. {
  1411. if( GET_LSSERVER_MAJOR_VERSION(dwVersion) <= 5 &&
  1412. GET_LSSERVER_MINOR_VERSION(dwVersion) <= 2 )
  1413. {
  1414. #if DBG
  1415. OutputDebugString(pwszServerTmp);
  1416. OutputDebugString(_TEXT(" old License Server\n"));
  1417. #endif
  1418. continue;
  1419. }
  1420. }
  1421. //
  1422. // No Beta <--> RTM server.
  1423. //
  1424. //
  1425. // TLSIsBetaNTServer() returns TRUE if eval NT
  1426. // IS_LSSERVER_RTM() returns TRUE if LS is an RTM.
  1427. //
  1428. if( TLSIsBetaNTServer() == IS_LSSERVER_RTM(dwVersion) )
  1429. {
  1430. continue;
  1431. }
  1432. #endif
  1433. if(dwVersion & TLS_VERSION_ENTERPRISE_BIT)
  1434. {
  1435. continue;
  1436. }
  1437. bCancel=pfCallBack(pContext, pwszServerTmp, dwUserData);
  1438. if (!fRegOnly)
  1439. {
  1440. //
  1441. // Add to list of servers
  1442. //
  1443. cchServer = wcslen(pwszServerTmp);
  1444. pwszServersTmp = (LPWSTR) LocalReAlloc(pwszServers,(cchServers+cchServer+1)*sizeof(TCHAR),LHND);
  1445. if (NULL == pwszServersTmp)
  1446. {
  1447. continue;
  1448. }
  1449. pwszServers = pwszServersTmp;
  1450. if (cchServers == 2)
  1451. {
  1452. wcscpy(pwszServers,pwszServerTmp);
  1453. cchServers += cchServer;
  1454. } else
  1455. {
  1456. wcscpy(pwszServers+cchServers-1,pwszServerTmp);
  1457. cchServers += cchServer + 1;
  1458. }
  1459. pwszServers[cchServers-1] = L'\0';
  1460. }
  1461. } while (FALSE);
  1462. if(bCancel == FALSE && pContext != NULL)
  1463. {
  1464. TLSDisconnectFromServer(pContext);
  1465. }
  1466. } while(bCancel == FALSE);
  1467. if (!fRegOnly)
  1468. {
  1469. WriteLicenseServersToReg(REG_DOMAIN_SERVER_MULTI,pwszServers,cchServers);
  1470. }
  1471. cleanup:
  1472. if(hClientSlot != INVALID_HANDLE_VALUE)
  1473. {
  1474. CloseHandle(hClientSlot);
  1475. }
  1476. if(hServerSlot != INVALID_HANDLE_VALUE)
  1477. {
  1478. CloseHandle(hServerSlot);
  1479. }
  1480. if (pwszServerNames)
  1481. LocalFree(pwszServerNames);
  1482. if (pwszServers)
  1483. LocalFree(pwszServers);
  1484. if (rgwszServers)
  1485. LocalFree(rgwszServers);
  1486. return dwStatus;
  1487. }
  1488. DWORD
  1489. GetServersFromRegistry(
  1490. LPWSTR wszRegKey,
  1491. LPWSTR **prgszServers,
  1492. DWORD *pcCount
  1493. )
  1494. {
  1495. HKEY hParamKey = NULL;
  1496. DWORD dwValueType;
  1497. DWORD cbValue = 0, dwDisp;
  1498. LONG lReturn;
  1499. DWORD cbServer;
  1500. DWORD cServers;
  1501. DWORD cchServerMax;
  1502. LPWSTR *rgszServers;
  1503. DWORD i, j;
  1504. *prgszServers = NULL;
  1505. *pcCount = 0;
  1506. lReturn = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1507. wszRegKey,
  1508. 0,
  1509. KEY_READ,
  1510. &hParamKey );
  1511. if (ERROR_SUCCESS != lReturn)
  1512. return lReturn;
  1513. lReturn = RegQueryInfoKey(hParamKey,
  1514. NULL,
  1515. NULL,
  1516. NULL,
  1517. &cServers,
  1518. &cchServerMax,
  1519. NULL,
  1520. NULL,
  1521. NULL,
  1522. NULL,
  1523. NULL,
  1524. NULL);
  1525. if (ERROR_SUCCESS != lReturn)
  1526. {
  1527. RegCloseKey( hParamKey );
  1528. return lReturn;
  1529. }
  1530. if (0 == cServers)
  1531. {
  1532. RegCloseKey( hParamKey );
  1533. return ERROR_NO_MORE_ITEMS;
  1534. }
  1535. rgszServers = (LPWSTR *) LocalAlloc(LPTR,cServers*sizeof(LPWSTR));
  1536. if (NULL == rgszServers)
  1537. {
  1538. RegCloseKey( hParamKey );
  1539. return ERROR_NOT_ENOUGH_MEMORY;
  1540. }
  1541. // Add one for null terminator
  1542. cchServerMax++;
  1543. for (i = 0; i < cServers; i++)
  1544. {
  1545. rgszServers[i] = (LPWSTR) LocalAlloc(LPTR,cchServerMax * sizeof(WCHAR));
  1546. if (NULL == rgszServers[i])
  1547. {
  1548. for (j = 0; j < i; j++)
  1549. {
  1550. LocalFree(rgszServers[j]);
  1551. }
  1552. LocalFree(rgszServers);
  1553. RegCloseKey( hParamKey );
  1554. return ERROR_NOT_ENOUGH_MEMORY;
  1555. }
  1556. cbServer = cchServerMax * sizeof(WCHAR);
  1557. lReturn = RegEnumKeyEx(hParamKey,
  1558. i,
  1559. rgszServers[i],
  1560. &cbServer,
  1561. NULL,
  1562. NULL,
  1563. NULL,
  1564. NULL);
  1565. if (ERROR_SUCCESS != lReturn)
  1566. {
  1567. for (j = 0; j <= i; j++)
  1568. {
  1569. LocalFree(rgszServers[j]);
  1570. }
  1571. LocalFree(rgszServers);
  1572. RegCloseKey( hParamKey );
  1573. return lReturn;
  1574. }
  1575. }
  1576. *prgszServers = rgszServers;
  1577. *pcCount = cServers;
  1578. return ERROR_SUCCESS;
  1579. }
  1580. DWORD WINAPI
  1581. EnumerateTlsServerInRegistry(
  1582. IN TLSENUMERATECALLBACK pfCallBack,
  1583. IN HANDLE dwUserData,
  1584. IN DWORD dwTimeOut,
  1585. LPWSTR wszRegKey
  1586. )
  1587. /*++
  1588. ++*/
  1589. {
  1590. BOOL bCancel=FALSE;
  1591. DWORD dwIndex = 0;
  1592. DWORD cServers = 0;
  1593. LPWSTR *rgszServers = NULL;
  1594. DWORD lReturn;
  1595. lReturn = GetServersFromRegistry(wszRegKey,
  1596. &rgszServers,
  1597. &cServers
  1598. );
  1599. if (ERROR_SUCCESS != lReturn)
  1600. {
  1601. return lReturn;
  1602. }
  1603. RandomizeArray(rgszServers,cServers);
  1604. for (;dwIndex < cServers; dwIndex++)
  1605. {
  1606. PCONTEXT_HANDLE pContext=NULL;
  1607. RPC_STATUS rpcStatus;
  1608. bCancel=pfCallBack(pContext, rgszServers[dwIndex], dwUserData);
  1609. if(bCancel == TRUE)
  1610. continue;
  1611. if(!(pContext = TLSConnectToLsServer(rgszServers[dwIndex])))
  1612. {
  1613. //
  1614. // could be access denied, or the machine is gone
  1615. //
  1616. continue;
  1617. }
  1618. do {
  1619. //
  1620. // Skip enterprise server
  1621. //
  1622. DWORD dwVersion;
  1623. rpcStatus = TLSGetVersion( pContext, &dwVersion );
  1624. if(rpcStatus != RPC_S_OK)
  1625. {
  1626. break;
  1627. }
  1628. #if ENFORCE_LICENSING
  1629. //
  1630. // W2K Beta 3 to RC1 upgrade, don't connect to any non-enforce
  1631. // server 5.2 or older
  1632. //
  1633. if(IS_ENFORCE_LSSERVER(dwVersion) == FALSE)
  1634. {
  1635. if( GET_LSSERVER_MAJOR_VERSION(dwVersion) <= 5 &&
  1636. GET_LSSERVER_MINOR_VERSION(dwVersion) <= 2 )
  1637. {
  1638. // old License Server
  1639. continue;
  1640. }
  1641. }
  1642. //
  1643. // Prevent beta <-> RTM server talking to each other
  1644. //
  1645. //
  1646. // TLSIsBetaNTServer() returns TRUE if eval NT
  1647. // IS_LSSERVER_RTM() returns TRUE if LS is an RTM.
  1648. //
  1649. if( TLSIsBetaNTServer() == IS_LSSERVER_RTM(dwVersion) )
  1650. {
  1651. continue;
  1652. }
  1653. #endif
  1654. if(dwVersion & TLS_VERSION_ENTERPRISE_BIT)
  1655. {
  1656. break;
  1657. }
  1658. bCancel=pfCallBack(pContext, rgszServers[dwIndex], dwUserData);
  1659. } while (FALSE);
  1660. if(bCancel == FALSE && pContext != NULL)
  1661. {
  1662. TLSDisconnect(&pContext);
  1663. }
  1664. } // for loop
  1665. for (dwIndex = 0; dwIndex < cServers; dwIndex++)
  1666. {
  1667. LocalFree(rgszServers[dwIndex]);
  1668. }
  1669. LocalFree(rgszServers);
  1670. return ERROR_SUCCESS;
  1671. }
  1672. DWORD WINAPI
  1673. EnumerateTlsServer(
  1674. IN TLSENUMERATECALLBACK pfCallBack,
  1675. IN HANDLE dwUserData,
  1676. IN DWORD dwTimeOut,
  1677. IN BOOL fRegOnly
  1678. )
  1679. /*++
  1680. ++*/
  1681. {
  1682. DWORD dwErr;
  1683. LPWSTR szDomain = NULL;
  1684. BOOL fOffSite = FALSE; // don't try to go off-site
  1685. //
  1686. // First check for a registry bypass of discovery
  1687. //
  1688. dwErr = EnumerateTlsServerInRegistry(
  1689. pfCallBack,
  1690. dwUserData,
  1691. dwTimeOut,
  1692. TEXT(TERMINAL_SERVICE_PARAM_DISCOVERY)
  1693. );
  1694. if ((!fRegOnly) || (g_fInDomain == -1))
  1695. {
  1696. //
  1697. // Check even if set (for !fRegOnly), to get domain name
  1698. //
  1699. dwErr = TLSInDomain(&g_fInDomain, fRegOnly ? NULL : &szDomain);
  1700. if (dwErr != NO_ERROR)
  1701. return dwErr;
  1702. }
  1703. //
  1704. // Reading registry failed, use full discovery
  1705. //
  1706. if(g_fInDomain)
  1707. {
  1708. dwErr = EnumerateTlsServerInDomain(
  1709. szDomain,
  1710. pfCallBack,
  1711. dwUserData,
  1712. dwTimeOut,
  1713. fRegOnly,
  1714. &fOffSite
  1715. );
  1716. if ((dwErr == NO_ERROR) && !fRegOnly)
  1717. {
  1718. g_fOffSiteLicenseServer = fOffSite;
  1719. }
  1720. }
  1721. else
  1722. {
  1723. dwErr = EnumerateTlsServerInWorkGroup(
  1724. pfCallBack,
  1725. dwUserData,
  1726. dwTimeOut,
  1727. fRegOnly
  1728. );
  1729. }
  1730. if (NULL != szDomain)
  1731. {
  1732. NetApiBufferFree(szDomain);
  1733. }
  1734. if ((NULL != g_hImmediateDiscovery)
  1735. && (dwErr != NO_ERROR) && fRegOnly)
  1736. {
  1737. SetEvent(g_hImmediateDiscovery);
  1738. }
  1739. if ((NULL != g_hDiscoverySoon)
  1740. && (dwErr == NO_ERROR) && fOffSite && !fRegOnly)
  1741. {
  1742. SetEvent(g_hDiscoverySoon);
  1743. }
  1744. return dwErr;
  1745. }
  1746. TLS_HANDLE
  1747. ConnectAndCheckServer(LPWSTR szServer)
  1748. {
  1749. TLS_HANDLE hBinding;
  1750. DWORD dwVersion;
  1751. RPC_STATUS rpcStatus;
  1752. hBinding = TLSConnectToLsServer(szServer);
  1753. if(hBinding == NULL)
  1754. {
  1755. goto done;
  1756. }
  1757. // Skip Windows 2000 License servers
  1758. DWORD dwSupportFlags = 0;
  1759. DWORD dwErrCode = 0;
  1760. dwErrCode = TLSGetSupportFlags(
  1761. hBinding,
  1762. &dwSupportFlags
  1763. );
  1764. if ((dwErrCode == RPC_S_OK) && !(dwSupportFlags & SUPPORT_WHISTLER_CAL))
  1765. {
  1766. TLSDisconnect(&hBinding);
  1767. goto done;
  1768. }
  1769. // If the call fails => Windows 2000 LS
  1770. else if(dwErrCode != RPC_S_OK)
  1771. {
  1772. TLSDisconnect(&hBinding);
  1773. goto done;
  1774. }
  1775. rpcStatus = TLSGetVersion(
  1776. hBinding,
  1777. &dwVersion
  1778. );
  1779. if(rpcStatus != RPC_S_OK)
  1780. {
  1781. TLSDisconnect(&hBinding);
  1782. goto done;
  1783. }
  1784. if( TLSIsBetaNTServer() == IS_LSSERVER_RTM(dwVersion) )
  1785. {
  1786. TLSDisconnect(&hBinding);
  1787. goto done;
  1788. }
  1789. done:
  1790. return hBinding;
  1791. }
  1792. //+------------------------------------------------------------------------
  1793. // Function: TLSConnectToAnyLsServer()
  1794. //
  1795. // Description:
  1796. //
  1797. // Routine to bind to any license server
  1798. //
  1799. // Arguments:
  1800. // dwTimeout - INFINITE for going off-site
  1801. //
  1802. // Return Value:
  1803. //
  1804. // RPC binding handle or NULL if error, use GetLastError() to retrieve
  1805. // detail error.
  1806. //-------------------------------------------------------------------------
  1807. TLS_HANDLE WINAPI
  1808. TLSConnectToAnyLsServer(
  1809. DWORD dwTimeout
  1810. )
  1811. /*++
  1812. ++*/
  1813. {
  1814. TLS_HANDLE hBinding=NULL;
  1815. HRESULT hr = S_OK;
  1816. LPWSTR *rgszServers = NULL;
  1817. DWORD cServers = 0;
  1818. DWORD i;
  1819. DWORD dwErr;
  1820. BOOL fInDomain;
  1821. LPWSTR szDomain = NULL;
  1822. LPWSTR szServerFound = NULL;
  1823. BOOL fRegOnly = (dwTimeout != INFINITE);
  1824. LPWSTR pwszServerNames = NULL;
  1825. BOOL fFreeServerNames = TRUE;
  1826. // TODO: add error codes/handling to all of this
  1827. //
  1828. // First check for a registry bypass of discovery
  1829. //
  1830. dwErr = GetServersFromRegistry(
  1831. TEXT(TERMINAL_SERVICE_PARAM_DISCOVERY),
  1832. &rgszServers,
  1833. &cServers
  1834. );
  1835. if (ERROR_SUCCESS == dwErr)
  1836. {
  1837. RandomizeArray(rgszServers,cServers);
  1838. for (i = 0; i < cServers; i++)
  1839. {
  1840. hBinding = ConnectAndCheckServer(rgszServers[i]);
  1841. if (NULL != hBinding)
  1842. {
  1843. szServerFound = rgszServers[i];
  1844. goto found_one;
  1845. }
  1846. }
  1847. if(NULL != rgszServers)
  1848. {
  1849. for (i = 0; i < cServers; i++)
  1850. {
  1851. LocalFree(rgszServers[i]);
  1852. }
  1853. LocalFree(rgszServers);
  1854. rgszServers = NULL;
  1855. }
  1856. }
  1857. //
  1858. // Next try Site (Enterprise) license servers
  1859. //
  1860. if (!fRegOnly)
  1861. {
  1862. hr = GetAllEnterpriseServers(&rgszServers,&cServers);
  1863. if (SUCCEEDED(hr))
  1864. {
  1865. RandomizeArray(rgszServers,cServers);
  1866. }
  1867. }
  1868. else
  1869. {
  1870. // rgszServers[i] is an index into pwszServerNames; don't free
  1871. fFreeServerNames = FALSE;
  1872. hr = GetLicenseServersFromReg(ENTERPRISE_SERVER_MULTI,
  1873. &pwszServerNames,
  1874. &cServers,
  1875. &rgszServers);
  1876. }
  1877. if (SUCCEEDED(hr))
  1878. {
  1879. for (i = 0; i < cServers; i++)
  1880. {
  1881. hBinding = ConnectAndCheckServer(rgszServers[i]);
  1882. if (NULL != hBinding)
  1883. {
  1884. szServerFound = rgszServers[i];
  1885. goto found_one;
  1886. }
  1887. }
  1888. if(NULL != rgszServers)
  1889. {
  1890. if (fFreeServerNames)
  1891. {
  1892. for (i = 0; i < cServers; i++)
  1893. {
  1894. LocalFree(rgszServers[i]);
  1895. }
  1896. LocalFree(rgszServers);
  1897. }
  1898. rgszServers = NULL;
  1899. }
  1900. }
  1901. //
  1902. // No Site LS found, try Domain/Workgroup servers
  1903. //
  1904. dwErr = TLSInDomain(&fInDomain, &szDomain);
  1905. if (dwErr != NO_ERROR)
  1906. return NULL;
  1907. LS_ENUM_PARAM param;
  1908. param.hBinding = &hBinding;
  1909. param.dwTimeout = INFINITE;
  1910. QueryPerformanceCounter(&(param.timeInitial));
  1911. fFreeServerNames = TRUE;
  1912. if (fInDomain)
  1913. {
  1914. BOOL fOffSite = TRUE;
  1915. dwErr = EnumerateTlsServerInDomain(
  1916. szDomain,
  1917. BindAnyServer,
  1918. &param,
  1919. INFINITE,
  1920. fRegOnly,
  1921. &fOffSite
  1922. );
  1923. if (dwErr == NO_ERROR)
  1924. {
  1925. g_fOffSiteLicenseServer = fOffSite;
  1926. }
  1927. }
  1928. else
  1929. {
  1930. dwErr = EnumerateTlsServerInWorkGroup(
  1931. BindAnyServer,
  1932. &param,
  1933. MAILSLOT_WAIT_FOREVER,
  1934. fRegOnly
  1935. );
  1936. }
  1937. if (NULL != szDomain)
  1938. {
  1939. NetApiBufferFree(szDomain);
  1940. }
  1941. if (hBinding != NULL)
  1942. goto found_one;
  1943. if (NULL != pwszServerNames)
  1944. {
  1945. LocalFree(pwszServerNames);
  1946. }
  1947. if ((NULL != g_hImmediateDiscovery)
  1948. && fRegOnly)
  1949. {
  1950. SetEvent(g_hImmediateDiscovery);
  1951. }
  1952. else if ((NULL != g_hDiscoverySoon)
  1953. && !fRegOnly && g_fOffSiteLicenseServer)
  1954. {
  1955. SetEvent(g_hDiscoverySoon);
  1956. }
  1957. return NULL;
  1958. found_one:
  1959. if (NULL != pwszServerNames)
  1960. {
  1961. LocalFree(pwszServerNames);
  1962. }
  1963. if(NULL != rgszServers)
  1964. {
  1965. if (fFreeServerNames)
  1966. {
  1967. for (i = 0; i < cServers; i++)
  1968. {
  1969. LocalFree(rgszServers[i]);
  1970. }
  1971. }
  1972. LocalFree(rgszServers);
  1973. }
  1974. return hBinding;
  1975. }
  1976. BOOL
  1977. TLSRefreshLicenseServerCache(
  1978. IN DWORD dwTimeOut
  1979. )
  1980. /*++
  1981. Abstract:
  1982. Refresh license server cache in registry.
  1983. Parameter:
  1984. dwTimeOut : Reserverd, should pass in INIFINITE for now
  1985. Returns:
  1986. TRUE/FALSE
  1987. --*/
  1988. {
  1989. BOOL bFoundServer = FALSE;
  1990. TLS_HANDLE hBinding = NULL;
  1991. hBinding = TLSConnectToAnyLsServer(dwTimeOut);
  1992. if (NULL != hBinding)
  1993. {
  1994. bFoundServer = TRUE;
  1995. TLSDisconnect(&hBinding);
  1996. }
  1997. return bFoundServer;
  1998. }
  1999. LICENSE_STATUS
  2000. InstallCertificate(LPVOID lpParam)
  2001. {
  2002. Sleep(INSTALL_CERT_DELAY);
  2003. return LsCsp_InstallX509Certificate(NULL);
  2004. }
  2005. //-------------------------------------------------------------------------
  2006. TLS_HANDLE WINAPI
  2007. TLSConnectToLsServer(
  2008. LPTSTR pszLsServer
  2009. )
  2010. /*++
  2011. ++*/
  2012. {
  2013. TCHAR szMachineName[MAX_COMPUTERNAME_LENGTH + 1] ;
  2014. PCONTEXT_HANDLE pContext=NULL;
  2015. DWORD cbMachineName=MAX_COMPUTERNAME_LENGTH;
  2016. HANDLE hThread = NULL;
  2017. static BOOL fLSFound = FALSE;
  2018. memset(szMachineName, 0, sizeof(szMachineName));
  2019. GetComputerName(szMachineName, &cbMachineName);
  2020. if(pszLsServer == NULL || _tcsicmp(szMachineName, pszLsServer) == 0)
  2021. {
  2022. pContext=ConnectLsServer(
  2023. szMachineName,
  2024. _TEXT(RPC_PROTOSEQLPC),
  2025. NULL,
  2026. RPC_C_AUTHN_LEVEL_DEFAULT
  2027. );
  2028. if(GetLastError() >= LSERVER_ERROR_BASE)
  2029. {
  2030. return NULL;
  2031. }
  2032. // try to connect with TCP protocol, if local procedure failed
  2033. }
  2034. if(pContext == NULL)
  2035. {
  2036. pContext=ConnectLsServer(
  2037. pszLsServer,
  2038. _TEXT(RPC_PROTOSEQNP),
  2039. _TEXT(LSNAMEPIPE),
  2040. RPC_C_AUTHN_LEVEL_NONE
  2041. );
  2042. }
  2043. if (!fLSFound && (NULL != pContext))
  2044. {
  2045. fLSFound = TRUE;
  2046. // Now that someone's connected, we can install a license
  2047. hThread = CreateThread(NULL,
  2048. 0,
  2049. InstallCertificate,
  2050. NULL,
  2051. 0,
  2052. NULL);
  2053. if (hThread != NULL)
  2054. {
  2055. CloseHandle(hThread);
  2056. }
  2057. else
  2058. {
  2059. // Can't create the thread; try again later
  2060. fLSFound = FALSE;
  2061. }
  2062. }
  2063. return (TLS_HANDLE) pContext;
  2064. }
  2065. //-------------------------------------------------------------------------
  2066. void WINAPI
  2067. TLSDisconnectFromServer(
  2068. TLS_HANDLE pHandle
  2069. )
  2070. /*++
  2071. ++*/
  2072. {
  2073. if(pHandle != NULL)
  2074. {
  2075. TLSDisconnect( &pHandle );
  2076. }
  2077. }
  2078. //----------------------------------------------------------------------------
  2079. DWORD WINAPI
  2080. TLSConnect(
  2081. handle_t binding,
  2082. TLS_HANDLE *ppHandle
  2083. )
  2084. /*++
  2085. ++*/
  2086. {
  2087. return TLSRpcConnect(binding, ppHandle);
  2088. }
  2089. //----------------------------------------------------------------------------
  2090. DWORD WINAPI
  2091. TLSDisconnect(
  2092. TLS_HANDLE* pphHandle
  2093. )
  2094. /*++
  2095. ++*/
  2096. {
  2097. RPC_STATUS rpc_status;
  2098. rpc_status = TLSRpcDisconnect( pphHandle );
  2099. if(rpc_status != RPC_S_OK)
  2100. {
  2101. RpcSmDestroyClientContext(pphHandle);
  2102. }
  2103. *pphHandle = NULL;
  2104. return ERROR_SUCCESS;
  2105. }
  2106. //-------------------------------------------------------------------------
  2107. DWORD WINAPI
  2108. TLSGetVersion (
  2109. IN TLS_HANDLE hHandle,
  2110. OUT PDWORD pdwVersion
  2111. )
  2112. /*++
  2113. ++*/
  2114. {
  2115. return TLSRpcGetVersion( hHandle, pdwVersion );
  2116. }
  2117. //----------------------------------------------------------------------------
  2118. DWORD WINAPI
  2119. TLSSendServerCertificate(
  2120. TLS_HANDLE hHandle,
  2121. DWORD cbCert,
  2122. PBYTE pbCert,
  2123. PDWORD pdwErrCode
  2124. )
  2125. /*++
  2126. ++*/
  2127. {
  2128. return TLSRpcSendServerCertificate(
  2129. hHandle,
  2130. cbCert,
  2131. pbCert,
  2132. pdwErrCode
  2133. );
  2134. }
  2135. //----------------------------------------------------------------------------
  2136. DWORD WINAPI
  2137. TLSGetServerName(
  2138. TLS_HANDLE hHandle,
  2139. LPTSTR szMachineName,
  2140. PDWORD pcbSize,
  2141. PDWORD pdwErrCode
  2142. )
  2143. /*++
  2144. ++*/
  2145. {
  2146. return TLSRpcGetServerName(
  2147. hHandle,
  2148. szMachineName,
  2149. pcbSize,
  2150. pdwErrCode
  2151. );
  2152. }
  2153. //----------------------------------------------------------------------------
  2154. DWORD WINAPI
  2155. TLSGetServerNameEx(
  2156. TLS_HANDLE hHandle,
  2157. LPTSTR szMachineName,
  2158. PDWORD pcbSize,
  2159. PDWORD pdwErrCode
  2160. )
  2161. /*++
  2162. ++*/
  2163. {
  2164. RPC_STATUS rpc_status;
  2165. rpc_status = TLSRpcGetServerNameEx(
  2166. hHandle,
  2167. szMachineName,
  2168. pcbSize,
  2169. pdwErrCode
  2170. );
  2171. if (rpc_status == RPC_S_PROCNUM_OUT_OF_RANGE)
  2172. {
  2173. rpc_status = TLSRpcGetServerName(
  2174. hHandle,
  2175. szMachineName,
  2176. pcbSize,
  2177. pdwErrCode
  2178. );
  2179. }
  2180. return rpc_status;
  2181. }
  2182. //----------------------------------------------------------------------------
  2183. DWORD WINAPI
  2184. TLSGetServerScope(
  2185. TLS_HANDLE hHandle,
  2186. LPTSTR szScopeName,
  2187. PDWORD pcbSize,
  2188. PDWORD pdwErrCode)
  2189. /*++
  2190. ++*/
  2191. {
  2192. return TLSRpcGetServerScope(
  2193. hHandle,
  2194. szScopeName,
  2195. pcbSize,
  2196. pdwErrCode
  2197. );
  2198. }
  2199. //----------------------------------------------------------------------------
  2200. DWORD WINAPI
  2201. TLSIssuePlatformChallenge(
  2202. TLS_HANDLE hHandle,
  2203. DWORD dwClientInfo,
  2204. PCHALLENGE_CONTEXT pChallengeContext,
  2205. PDWORD pcbChallengeData,
  2206. PBYTE* pChallengeData,
  2207. PDWORD pdwErrCode
  2208. )
  2209. /*++
  2210. ++*/
  2211. {
  2212. return TLSRpcIssuePlatformChallenge(
  2213. hHandle,
  2214. dwClientInfo,
  2215. pChallengeContext,
  2216. pcbChallengeData,
  2217. pChallengeData,
  2218. pdwErrCode
  2219. );
  2220. }
  2221. //----------------------------------------------------------------------------
  2222. DWORD WINAPI
  2223. TLSIssueNewLicense(
  2224. TLS_HANDLE hHandle,
  2225. CHALLENGE_CONTEXT ChallengeContext,
  2226. LICENSEREQUEST *pRequest,
  2227. LPTSTR pMachineName,
  2228. LPTSTR pUserName,
  2229. DWORD cbChallengeResponse,
  2230. PBYTE pbChallengeResponse,
  2231. BOOL bAcceptTemporaryLicense,
  2232. PDWORD pcbLicense,
  2233. PBYTE* ppbLicense,
  2234. PDWORD pdwErrCode
  2235. )
  2236. /*++
  2237. ++*/
  2238. {
  2239. TLSLICENSEREQUEST rpcRequest;
  2240. RequestToTlsRequest( pRequest, &rpcRequest );
  2241. return TLSRpcRequestNewLicense(
  2242. hHandle,
  2243. ChallengeContext,
  2244. &rpcRequest,
  2245. pMachineName,
  2246. pUserName,
  2247. cbChallengeResponse,
  2248. pbChallengeResponse,
  2249. bAcceptTemporaryLicense,
  2250. pcbLicense,
  2251. ppbLicense,
  2252. pdwErrCode
  2253. );
  2254. }
  2255. //----------------------------------------------------------------------------
  2256. DWORD WINAPI
  2257. TLSIssueNewLicenseEx(
  2258. TLS_HANDLE hHandle,
  2259. PDWORD pSupportFlags,
  2260. CHALLENGE_CONTEXT ChallengeContext,
  2261. LICENSEREQUEST *pRequest,
  2262. LPTSTR pMachineName,
  2263. LPTSTR pUserName,
  2264. DWORD cbChallengeResponse,
  2265. PBYTE pbChallengeResponse,
  2266. BOOL bAcceptTemporaryLicense,
  2267. DWORD dwQuantity,
  2268. PDWORD pcbLicense,
  2269. PBYTE* ppbLicense,
  2270. PDWORD pdwErrCode
  2271. )
  2272. /*++
  2273. ++*/
  2274. {
  2275. DWORD dwStatus;
  2276. TLSLICENSEREQUEST rpcRequest;
  2277. RequestToTlsRequest( pRequest, &rpcRequest );
  2278. dwStatus = TLSRpcRequestNewLicenseEx(
  2279. hHandle,
  2280. pSupportFlags,
  2281. ChallengeContext,
  2282. &rpcRequest,
  2283. pMachineName,
  2284. pUserName,
  2285. cbChallengeResponse,
  2286. pbChallengeResponse,
  2287. bAcceptTemporaryLicense,
  2288. dwQuantity,
  2289. pcbLicense,
  2290. ppbLicense,
  2291. pdwErrCode
  2292. );
  2293. if (dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE)
  2294. {
  2295. *pSupportFlags = 0;
  2296. dwStatus = TLSRpcRequestNewLicense(
  2297. hHandle,
  2298. ChallengeContext,
  2299. &rpcRequest,
  2300. pMachineName,
  2301. pUserName,
  2302. cbChallengeResponse,
  2303. pbChallengeResponse,
  2304. bAcceptTemporaryLicense,
  2305. pcbLicense,
  2306. ppbLicense,
  2307. pdwErrCode
  2308. );
  2309. }
  2310. return(dwStatus);
  2311. }
  2312. //----------------------------------------------------------------------------
  2313. DWORD WINAPI
  2314. TLSIssueNewLicenseExEx(
  2315. TLS_HANDLE hHandle,
  2316. PDWORD pSupportFlags,
  2317. CHALLENGE_CONTEXT ChallengeContext,
  2318. LICENSEREQUEST *pRequest,
  2319. LPTSTR pMachineName,
  2320. LPTSTR pUserName,
  2321. DWORD cbChallengeResponse,
  2322. PBYTE pbChallengeResponse,
  2323. BOOL bAcceptTemporaryLicense,
  2324. BOOL bAcceptFewerLicenses,
  2325. DWORD *pdwQuantity,
  2326. PDWORD pcbLicense,
  2327. PBYTE* ppbLicense,
  2328. PDWORD pdwErrCode
  2329. )
  2330. /*++
  2331. ++*/
  2332. {
  2333. DWORD dwStatus;
  2334. TLSLICENSEREQUEST rpcRequest;
  2335. RequestToTlsRequest( pRequest, &rpcRequest );
  2336. dwStatus = TLSRpcRequestNewLicenseExEx(
  2337. hHandle,
  2338. pSupportFlags,
  2339. ChallengeContext,
  2340. &rpcRequest,
  2341. pMachineName,
  2342. pUserName,
  2343. cbChallengeResponse,
  2344. pbChallengeResponse,
  2345. bAcceptTemporaryLicense,
  2346. bAcceptFewerLicenses,
  2347. pdwQuantity,
  2348. pcbLicense,
  2349. ppbLicense,
  2350. pdwErrCode
  2351. );
  2352. if (dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE)
  2353. {
  2354. dwStatus = TLSRpcRequestNewLicenseEx(
  2355. hHandle,
  2356. pSupportFlags,
  2357. ChallengeContext,
  2358. &rpcRequest,
  2359. pMachineName,
  2360. pUserName,
  2361. cbChallengeResponse,
  2362. pbChallengeResponse,
  2363. bAcceptTemporaryLicense,
  2364. *pdwQuantity,
  2365. pcbLicense,
  2366. ppbLicense,
  2367. pdwErrCode
  2368. );
  2369. if (dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE)
  2370. {
  2371. *pSupportFlags = 0;
  2372. dwStatus = TLSRpcRequestNewLicense(
  2373. hHandle,
  2374. ChallengeContext,
  2375. &rpcRequest,
  2376. pMachineName,
  2377. pUserName,
  2378. cbChallengeResponse,
  2379. pbChallengeResponse,
  2380. bAcceptTemporaryLicense,
  2381. pcbLicense,
  2382. ppbLicense,
  2383. pdwErrCode
  2384. );
  2385. }
  2386. }
  2387. return(dwStatus);
  2388. }
  2389. //----------------------------------------------------------------------------
  2390. DWORD WINAPI
  2391. TLSUpgradeLicense(
  2392. TLS_HANDLE hHandle,
  2393. LICENSEREQUEST *pRequest,
  2394. CHALLENGE_CONTEXT ChallengeContext,
  2395. DWORD cbChallengeResponse,
  2396. PBYTE pbChallengeResponse,
  2397. DWORD cbOldLicense,
  2398. PBYTE pbOldLicense,
  2399. PDWORD pcbNewLicense,
  2400. PBYTE* ppbNewLicense,
  2401. PDWORD pdwErrCode
  2402. )
  2403. /*++
  2404. ++*/
  2405. {
  2406. TLSLICENSEREQUEST rpcRequest;
  2407. RequestToTlsRequest( pRequest, &rpcRequest );
  2408. return TLSRpcUpgradeLicense(
  2409. hHandle,
  2410. &rpcRequest,
  2411. ChallengeContext,
  2412. cbChallengeResponse,
  2413. pbChallengeResponse,
  2414. cbOldLicense,
  2415. pbOldLicense,
  2416. pcbNewLicense,
  2417. ppbNewLicense,
  2418. pdwErrCode
  2419. );
  2420. }
  2421. //----------------------------------------------------------------------------
  2422. DWORD WINAPI
  2423. TLSUpgradeLicenseEx(
  2424. TLS_HANDLE hHandle,
  2425. PDWORD pSupportFlags,
  2426. LICENSEREQUEST *pRequest,
  2427. CHALLENGE_CONTEXT ChallengeContext,
  2428. DWORD cbChallengeResponse,
  2429. PBYTE pbChallengeResponse,
  2430. DWORD cbOldLicense,
  2431. PBYTE pbOldLicense,
  2432. DWORD dwQuantity,
  2433. PDWORD pcbNewLicense,
  2434. PBYTE* ppbNewLicense,
  2435. PDWORD pdwErrCode
  2436. )
  2437. /*++
  2438. ++*/
  2439. {
  2440. DWORD dwStatus;
  2441. TLSLICENSEREQUEST rpcRequest;
  2442. RequestToTlsRequest( pRequest, &rpcRequest );
  2443. dwStatus = TLSRpcUpgradeLicenseEx(
  2444. hHandle,
  2445. pSupportFlags,
  2446. &rpcRequest,
  2447. ChallengeContext,
  2448. cbChallengeResponse,
  2449. pbChallengeResponse,
  2450. cbOldLicense,
  2451. pbOldLicense,
  2452. dwQuantity,
  2453. pcbNewLicense,
  2454. ppbNewLicense,
  2455. pdwErrCode
  2456. );
  2457. if (dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE)
  2458. {
  2459. *pSupportFlags = 0;
  2460. dwStatus = TLSRpcUpgradeLicense(
  2461. hHandle,
  2462. &rpcRequest,
  2463. ChallengeContext,
  2464. cbChallengeResponse,
  2465. pbChallengeResponse,
  2466. cbOldLicense,
  2467. pbOldLicense,
  2468. pcbNewLicense,
  2469. ppbNewLicense,
  2470. pdwErrCode
  2471. );
  2472. }
  2473. return(dwStatus);
  2474. }
  2475. //----------------------------------------------------------------------------
  2476. DWORD WINAPI
  2477. TLSAllocateConcurrentLicense(
  2478. TLS_HANDLE hHandle,
  2479. LPTSTR szHydraServer,
  2480. LICENSEREQUEST *pRequest,
  2481. LONG *dwQuantity,
  2482. PDWORD pdwErrCode
  2483. )
  2484. /*++
  2485. ++*/
  2486. {
  2487. TLSLICENSEREQUEST rpcRequest;
  2488. RequestToTlsRequest( pRequest, &rpcRequest );
  2489. return TLSRpcAllocateConcurrentLicense(
  2490. hHandle,
  2491. szHydraServer,
  2492. &rpcRequest,
  2493. dwQuantity,
  2494. pdwErrCode
  2495. );
  2496. }
  2497. //----------------------------------------------------------------------------
  2498. DWORD WINAPI
  2499. TLSGetLastError(
  2500. TLS_HANDLE hHandle,
  2501. DWORD cbBufferSize,
  2502. LPTSTR pszBuffer,
  2503. PDWORD pdwErrCode
  2504. )
  2505. /*++
  2506. ++*/
  2507. {
  2508. return TLSRpcGetLastError(
  2509. hHandle,
  2510. &cbBufferSize,
  2511. pszBuffer,
  2512. pdwErrCode
  2513. );
  2514. }
  2515. //----------------------------------------------------------------------------
  2516. DWORD WINAPI
  2517. TLSKeyPackEnumBegin(
  2518. TLS_HANDLE hHandle,
  2519. DWORD dwSearchParm,
  2520. BOOL bMatchAll,
  2521. LPLSKeyPackSearchParm lpSearchParm,
  2522. PDWORD pdwErrCode
  2523. )
  2524. /*++
  2525. ++*/
  2526. {
  2527. return TLSRpcKeyPackEnumBegin(
  2528. hHandle,
  2529. dwSearchParm,
  2530. bMatchAll,
  2531. lpSearchParm,
  2532. pdwErrCode
  2533. );
  2534. }
  2535. //----------------------------------------------------------------------------
  2536. DWORD WINAPI
  2537. TLSKeyPackEnumNext(
  2538. TLS_HANDLE hHandle,
  2539. LPLSKeyPack lpKeyPack,
  2540. PDWORD pdwErrCode
  2541. )
  2542. /*++
  2543. ++*/
  2544. {
  2545. return TLSRpcKeyPackEnumNext(
  2546. hHandle,
  2547. lpKeyPack,
  2548. pdwErrCode
  2549. );
  2550. }
  2551. //----------------------------------------------------------------------------
  2552. DWORD WINAPI
  2553. TLSKeyPackEnumEnd(
  2554. TLS_HANDLE hHandle,
  2555. PDWORD pdwErrCode
  2556. )
  2557. /*++
  2558. ++*/
  2559. {
  2560. return TLSRpcKeyPackEnumEnd(hHandle, pdwErrCode);
  2561. }
  2562. //----------------------------------------------------------------------------
  2563. DWORD WINAPI
  2564. TLSLicenseEnumBegin(
  2565. TLS_HANDLE hHandle,
  2566. DWORD dwSearchParm,
  2567. BOOL bMatchAll,
  2568. LPLSLicenseSearchParm lpSearchParm,
  2569. PDWORD pdwErrCode
  2570. )
  2571. /*++
  2572. ++*/
  2573. {
  2574. return TLSRpcLicenseEnumBegin(
  2575. hHandle,
  2576. dwSearchParm,
  2577. bMatchAll,
  2578. lpSearchParm,
  2579. pdwErrCode
  2580. );
  2581. }
  2582. //----------------------------------------------------------------------------
  2583. DWORD WINAPI
  2584. TLSLicenseEnumNext(
  2585. TLS_HANDLE hHandle,
  2586. LPLSLicense lpLicense,
  2587. PDWORD pdwErrCode
  2588. )
  2589. /*++
  2590. ++*/
  2591. {
  2592. return TLSRpcLicenseEnumNext(
  2593. hHandle,
  2594. lpLicense,
  2595. pdwErrCode
  2596. );
  2597. }
  2598. //----------------------------------------------------------------------------
  2599. DWORD WINAPI
  2600. TLSLicenseEnumNextEx(
  2601. TLS_HANDLE hHandle,
  2602. LPLSLicenseEx lpLicenseEx,
  2603. PDWORD pdwErrCode
  2604. )
  2605. /*++
  2606. ++*/
  2607. {
  2608. DWORD dwRet;
  2609. if (NULL == lpLicenseEx)
  2610. {
  2611. return ERROR_INVALID_PARAMETER;
  2612. }
  2613. dwRet = TLSRpcLicenseEnumNextEx(
  2614. hHandle,
  2615. lpLicenseEx,
  2616. pdwErrCode
  2617. );
  2618. if (RPC_S_PROCNUM_OUT_OF_RANGE == dwRet)
  2619. {
  2620. LSLicense License;
  2621. dwRet = TLSRpcLicenseEnumNext(
  2622. hHandle,
  2623. &License,
  2624. pdwErrCode
  2625. );
  2626. if ((dwRet == RPC_S_OK)
  2627. && (NULL != pdwErrCode)
  2628. && (*pdwErrCode == ERROR_SUCCESS))
  2629. {
  2630. // older versions only support quantity == 1
  2631. memcpy(lpLicenseEx,&License,sizeof(License));
  2632. lpLicenseEx->dwQuantity = 1;
  2633. }
  2634. }
  2635. return dwRet;
  2636. }
  2637. //----------------------------------------------------------------------------
  2638. DWORD WINAPI
  2639. TLSLicenseEnumEnd(
  2640. TLS_HANDLE hHandle,
  2641. PDWORD pdwErrCode
  2642. )
  2643. /*++
  2644. ++*/
  2645. {
  2646. return TLSRpcLicenseEnumEnd(hHandle, pdwErrCode);
  2647. }
  2648. //----------------------------------------------------------------------------
  2649. DWORD WINAPI
  2650. TLSGetAvailableLicenses(
  2651. TLS_HANDLE hHandle,
  2652. DWORD dwSearchParm,
  2653. LPLSKeyPack lplsKeyPack,
  2654. LPDWORD lpdwAvail,
  2655. PDWORD pdwErrCode
  2656. )
  2657. /*++
  2658. ++*/
  2659. {
  2660. return TLSRpcGetAvailableLicenses(
  2661. hHandle,
  2662. dwSearchParm,
  2663. lplsKeyPack,
  2664. lpdwAvail,
  2665. pdwErrCode
  2666. );
  2667. }
  2668. //----------------------------------------------------------------------------
  2669. DWORD WINAPI
  2670. TLSGetRevokeKeyPackList(
  2671. TLS_HANDLE hHandle,
  2672. PDWORD pcbNumberOfRange,
  2673. LPLSRange *ppRevokeRange,
  2674. PDWORD pdwErrCode
  2675. )
  2676. /*++
  2677. ++*/
  2678. {
  2679. return TLSRpcGetRevokeKeyPackList(
  2680. hHandle,
  2681. pcbNumberOfRange,
  2682. ppRevokeRange,
  2683. pdwErrCode
  2684. );
  2685. }
  2686. //----------------------------------------------------------------------------
  2687. DWORD WINAPI
  2688. TLSGetRevokeLicenseList(
  2689. TLS_HANDLE hHandle,
  2690. PDWORD pcbNumberOfRange,
  2691. LPLSRange *ppRevokeRange,
  2692. PDWORD pdwErrCode
  2693. )
  2694. /*++
  2695. ++*/
  2696. {
  2697. return TLSRpcGetRevokeLicenseList(
  2698. hHandle,
  2699. pcbNumberOfRange,
  2700. ppRevokeRange,
  2701. pdwErrCode
  2702. );
  2703. }
  2704. //----------------------------------------------------------------------------
  2705. DWORD WINAPI
  2706. TLSMarkLicense(
  2707. TLS_HANDLE hHandle,
  2708. UCHAR ucFlags,
  2709. DWORD cbLicense,
  2710. PBYTE pLicense,
  2711. PDWORD pdwErrCode
  2712. )
  2713. /*++
  2714. ++*/
  2715. {
  2716. return TLSRpcMarkLicense(
  2717. hHandle,
  2718. ucFlags,
  2719. cbLicense,
  2720. pLicense,
  2721. pdwErrCode
  2722. );
  2723. }
  2724. //----------------------------------------------------------------------------
  2725. DWORD WINAPI
  2726. TLSCheckLicenseMark(
  2727. TLS_HANDLE hHandle,
  2728. DWORD cbLicense,
  2729. PBYTE pLicense,
  2730. PUCHAR pucFlags,
  2731. PDWORD pdwErrCode
  2732. )
  2733. /*++
  2734. ++*/
  2735. {
  2736. return TLSRpcCheckLicenseMark(
  2737. hHandle,
  2738. cbLicense,
  2739. pLicense,
  2740. pucFlags,
  2741. pdwErrCode
  2742. );
  2743. }
  2744. //----------------------------------------------------------------------------
  2745. DWORD WINAPI
  2746. TLSGetSupportFlags(
  2747. TLS_HANDLE hHandle,
  2748. DWORD *pdwSupportFlags
  2749. )
  2750. /*++
  2751. ++*/
  2752. {
  2753. return TLSRpcGetSupportFlags(
  2754. hHandle,
  2755. pdwSupportFlags
  2756. );
  2757. }