Leaked source code of windows server 2003
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.

1790 lines
43 KiB

  1. //+-----------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-1996
  5. //
  6. // File: srvlist.cpp
  7. //
  8. // Contents: List of registed server
  9. //
  10. // History: 09-09-98 HueiWang Created
  11. //
  12. //-------------------------------------------------------------
  13. #include "pch.cpp"
  14. #include "srvlist.h"
  15. #include "globals.h"
  16. #include "srvdef.h"
  17. #define STRSAFE_NO_DEPRECATE
  18. #include "strsafe.h"
  19. CTLServerMgr g_ServerMgr;
  20. ///////////////////////////////////////////////////////////////
  21. DWORD
  22. GetPageSize( VOID ) {
  23. static DWORD dwPageSize = 0;
  24. if ( !dwPageSize ) {
  25. SYSTEM_INFO sysInfo = { 0 };
  26. GetSystemInfo( &sysInfo ); // cannot fail.
  27. dwPageSize = sysInfo.dwPageSize;
  28. }
  29. return dwPageSize;
  30. }
  31. /*++**************************************************************
  32. NAME: MyVirtualAlloc
  33. as Malloc, but automatically protects the last page of the
  34. allocation. This simulates pageheap behavior without requiring
  35. it.
  36. MODIFIES: ppvData -- receives memory
  37. TAKES: dwSize -- minimum amount of data to get
  38. RETURNS: TRUE when the function succeeds.
  39. FALSE otherwise.
  40. LASTERROR: not set
  41. Free with MyVirtualFree
  42. **************************************************************--*/
  43. BOOL
  44. MyVirtualAlloc( IN DWORD dwSize,
  45. OUT PVOID *ppvData )
  46. {
  47. PBYTE pbData;
  48. DWORD dwTotalSize;
  49. PVOID pvLastPage;
  50. // ensure that we allocate one extra page
  51. dwTotalSize = dwSize / GetPageSize();
  52. if( dwSize % GetPageSize() ) {
  53. dwTotalSize ++;
  54. }
  55. // this is the guard page
  56. dwTotalSize++;
  57. dwTotalSize *= GetPageSize();
  58. // do the alloc
  59. pbData = (PBYTE) VirtualAlloc( NULL, // don't care where
  60. dwTotalSize,
  61. MEM_COMMIT |
  62. MEM_TOP_DOWN,
  63. PAGE_READWRITE );
  64. if ( pbData ) {
  65. pbData += dwTotalSize;
  66. // find the LAST page.
  67. pbData -= GetPageSize();
  68. pvLastPage = pbData;
  69. // now, carve out a chunk for the caller:
  70. pbData -= dwSize;
  71. // last, protect the last page:
  72. if ( VirtualProtect( pvLastPage,
  73. 1, // protect the page containing the last byte
  74. PAGE_NOACCESS,
  75. &dwSize ) ) {
  76. *ppvData = pbData;
  77. return TRUE;
  78. }
  79. VirtualFree( pbData, 0, MEM_RELEASE );
  80. }
  81. return FALSE;
  82. }
  83. VOID
  84. MyVirtualFree( IN PVOID pvData )
  85. {
  86. VirtualFree( pvData, 0, MEM_RELEASE );
  87. }
  88. ///////////////////////////////////////////////////////////////
  89. RPC_STATUS
  90. TryLookupServer(PCONTEXT_HANDLE hBinding,
  91. LPTSTR pszLookupSetupId,
  92. LPTSTR *pszLsSetupId,
  93. LPTSTR *pszDomainName,
  94. LPTSTR *pszLsName,
  95. PDWORD pdwErrCode)
  96. {
  97. RPC_STATUS status;
  98. DWORD dwErrCode;
  99. status = TLSLookupServerFixed(hBinding,
  100. pszLookupSetupId,
  101. pszLsSetupId,
  102. pszDomainName,
  103. pszLsName,
  104. pdwErrCode);
  105. if(status != RPC_S_OK)
  106. {
  107. LPTSTR lpszSetupId = NULL;
  108. LPTSTR lpszDomainName = NULL;
  109. LPTSTR lpszServerName = NULL;
  110. status = ERROR_NOACCESS;
  111. size_t cbError;
  112. try
  113. {
  114. if ( !MyVirtualAlloc( (LSERVER_MAX_STRING_SIZE+2) * sizeof( TCHAR ),
  115. (PVOID*) &lpszSetupId ) )
  116. {
  117. return RPC_S_OUT_OF_MEMORY;
  118. }
  119. memset(lpszSetupId, 0, ( LSERVER_MAX_STRING_SIZE +2 ) * sizeof( TCHAR ));
  120. if ( !MyVirtualAlloc( (LSERVER_MAX_STRING_SIZE+2) * sizeof( TCHAR ),
  121. (PVOID*) &lpszDomainName ) )
  122. {
  123. status = RPC_S_OUT_OF_MEMORY;
  124. goto cleanup;
  125. }
  126. memset(lpszDomainName, 0, ( LSERVER_MAX_STRING_SIZE +2 ) * sizeof( TCHAR ));
  127. if ( !MyVirtualAlloc( (MAX_COMPUTERNAME_LENGTH+2) * sizeof( TCHAR ),
  128. (PVOID*) &lpszServerName ) )
  129. {
  130. status = RPC_S_OUT_OF_MEMORY;
  131. goto cleanup;
  132. }
  133. memset(lpszServerName, 0, ( MAX_COMPUTERNAME_LENGTH +2 ) * sizeof( TCHAR ));
  134. DWORD cbSetupId = LSERVER_MAX_STRING_SIZE+1;
  135. DWORD cbDomainName = LSERVER_MAX_STRING_SIZE+1;
  136. DWORD cbServerName = MAX_COMPUTERNAME_LENGTH+1;
  137. status = TLSLookupServer(hBinding,
  138. pszLookupSetupId,
  139. lpszSetupId,
  140. &cbSetupId,
  141. lpszDomainName,
  142. &cbDomainName,
  143. lpszServerName,
  144. &cbServerName,
  145. pdwErrCode);
  146. if((status == RPC_S_OK) && (pdwErrCode != NULL) && (*pdwErrCode == ERROR_SUCCESS))
  147. {
  148. if (NULL != pszLsSetupId)
  149. {
  150. size_t cb;
  151. if (SUCCEEDED(StringCbLength(lpszSetupId,cbSetupId,&cb)))
  152. {
  153. *pszLsSetupId = (LPTSTR) MIDL_user_allocate(cb+sizeof(TCHAR));
  154. if (NULL != *pszLsSetupId)
  155. {
  156. lstrcpy(*pszLsSetupId,lpszSetupId);
  157. }
  158. else
  159. {
  160. status = RPC_S_OUT_OF_MEMORY;
  161. goto cleanup;
  162. }
  163. }
  164. else
  165. {
  166. status = RPC_S_INVALID_ARG;
  167. goto cleanup;
  168. }
  169. }
  170. if (NULL != pszDomainName)
  171. {
  172. size_t cb;
  173. if (SUCCEEDED(StringCbLength(lpszDomainName,cbDomainName,&cb)))
  174. {
  175. *pszDomainName = (LPTSTR) MIDL_user_allocate(cb+sizeof(TCHAR));
  176. if (NULL != *pszDomainName)
  177. {
  178. lstrcpy(*pszDomainName,lpszDomainName);
  179. }
  180. else
  181. {
  182. MIDL_user_free(*pszLsSetupId);
  183. status = RPC_S_OUT_OF_MEMORY;
  184. goto cleanup;
  185. }
  186. }
  187. else
  188. {
  189. MIDL_user_free(*pszLsSetupId);
  190. status = RPC_S_INVALID_ARG;
  191. goto cleanup;
  192. }
  193. }
  194. if (NULL != pszLsName)
  195. {
  196. size_t cb;
  197. if (SUCCEEDED(StringCbLength(lpszServerName,cbServerName,&cb)))
  198. {
  199. *pszLsName = (LPTSTR) MIDL_user_allocate(cb+sizeof(TCHAR));
  200. if (NULL != *pszLsName)
  201. {
  202. lstrcpy(*pszLsName,lpszServerName);
  203. }
  204. else
  205. {
  206. MIDL_user_free(*pszLsSetupId);
  207. MIDL_user_free(*pszDomainName);
  208. status = RPC_S_OUT_OF_MEMORY;
  209. goto cleanup;
  210. }
  211. }
  212. else
  213. {
  214. MIDL_user_free(*pszLsSetupId);
  215. MIDL_user_free(*pszDomainName);
  216. status = RPC_S_INVALID_ARG;
  217. goto cleanup;
  218. }
  219. }
  220. }
  221. }
  222. catch (...)
  223. {
  224. status = ERROR_NOACCESS;
  225. }
  226. cleanup:
  227. if(lpszSetupId)
  228. MyVirtualFree(lpszSetupId);
  229. if(lpszDomainName)
  230. MyVirtualFree(lpszDomainName);
  231. if(lpszServerName)
  232. MyVirtualFree(lpszServerName);
  233. }
  234. return status;
  235. }
  236. RPC_STATUS
  237. TryGetServerName(PCONTEXT_HANDLE hBinding,
  238. LPTSTR *pszServer,
  239. DWORD *pdwErrCode)
  240. {
  241. RPC_STATUS status;
  242. status = TLSGetServerNameFixed(hBinding,pszServer,pdwErrCode);
  243. if (status != RPC_S_OK)
  244. {
  245. LPTSTR lpszMachineName = NULL;
  246. try
  247. {
  248. if ( !MyVirtualAlloc( ( MAX_COMPUTERNAME_LENGTH+1 ) * sizeof( TCHAR ),
  249. (PVOID*) &lpszMachineName ) )
  250. {
  251. return RPC_S_OUT_OF_MEMORY;
  252. }
  253. DWORD uSize = MAX_COMPUTERNAME_LENGTH+1 ;
  254. memset(lpszMachineName, 0, ( MAX_COMPUTERNAME_LENGTH+1 ) * sizeof( TCHAR ));
  255. status = TLSGetServerNameEx(hBinding, lpszMachineName, &uSize, pdwErrCode);
  256. if((status == RPC_S_OK) && (pdwErrCode != NULL) && (*pdwErrCode == ERROR_SUCCESS))
  257. {
  258. size_t cb;
  259. if (SUCCEEDED(StringCbLength(lpszMachineName,( MAX_COMPUTERNAME_LENGTH+1 ) * sizeof( TCHAR ),&cb)))
  260. {
  261. *pszServer = (LPTSTR) MIDL_user_allocate(cb+sizeof(TCHAR));
  262. if (NULL != *pszServer)
  263. {
  264. lstrcpy(*pszServer,lpszMachineName);
  265. }
  266. else
  267. {
  268. status = RPC_S_OUT_OF_MEMORY;
  269. }
  270. }
  271. else
  272. {
  273. status = RPC_S_INVALID_ARG;
  274. }
  275. }
  276. }
  277. catch(...)
  278. {
  279. status = ERROR_NOACCESS;
  280. }
  281. if(lpszMachineName)
  282. MyVirtualFree(lpszMachineName);
  283. }
  284. return status;
  285. }
  286. RPC_STATUS
  287. TryGetServerScope(PCONTEXT_HANDLE hBinding,
  288. LPTSTR *pszScope,
  289. DWORD *pdwErrCode)
  290. {
  291. RPC_STATUS status;
  292. status = TLSGetServerScopeFixed(hBinding,pszScope,pdwErrCode);
  293. if (status != RPC_S_OK)
  294. {
  295. LPTSTR lpszScope = NULL;
  296. DWORD uSize = LSERVER_MAX_STRING_SIZE + 2;
  297. try
  298. {
  299. if ( !MyVirtualAlloc( ( LSERVER_MAX_STRING_SIZE + 2 ) * sizeof( TCHAR ),
  300. (PVOID*) &lpszScope ) )
  301. {
  302. return RPC_S_OUT_OF_MEMORY;
  303. }
  304. memset(lpszScope, 0, ( LSERVER_MAX_STRING_SIZE + 2 ) * sizeof( TCHAR ));
  305. status = TLSGetServerScope(hBinding, lpszScope, &uSize, pdwErrCode);
  306. if((status == RPC_S_OK) && (pdwErrCode != NULL) && (*pdwErrCode == ERROR_SUCCESS))
  307. {
  308. size_t cb;
  309. if (SUCCEEDED(StringCbLength(lpszScope, ( LSERVER_MAX_STRING_SIZE + 2 ) * sizeof( TCHAR ), &cb)))
  310. {
  311. *pszScope = (LPTSTR) MIDL_user_allocate(cb+sizeof(TCHAR));
  312. if (NULL != *pszScope)
  313. {
  314. lstrcpy(*pszScope,lpszScope);
  315. }
  316. else
  317. {
  318. status = RPC_S_OUT_OF_MEMORY;
  319. }
  320. }
  321. else
  322. {
  323. status = RPC_S_INVALID_ARG;
  324. }
  325. }
  326. }
  327. catch(...)
  328. {
  329. status = ERROR_NOACCESS;
  330. }
  331. if(lpszScope)
  332. MyVirtualFree(lpszScope);
  333. }
  334. return status;
  335. }
  336. DWORD
  337. TLSResolveServerIdToServer(
  338. LPTSTR pszServerId,
  339. DWORD cbServerName,
  340. LPTSTR pszServerName
  341. )
  342. /*++
  343. --*/
  344. {
  345. DWORD dwStatus = ERROR_SUCCESS;
  346. TLS_HANDLE hEServer = NULL;
  347. TLServerInfo EServerInfo;
  348. DWORD dwErrCode;
  349. TCHAR *szSetupId = NULL;
  350. TCHAR *szDomainName = NULL;
  351. TCHAR *szServerName = NULL;
  352. dwStatus = TLSLookupServerById(
  353. pszServerId,
  354. pszServerName
  355. );
  356. if(dwStatus != ERROR_SUCCESS)
  357. {
  358. // try to resolve server name with enterprise server
  359. dwStatus = TLSLookupAnyEnterpriseServer(&EServerInfo);
  360. if(dwStatus == ERROR_SUCCESS)
  361. {
  362. hEServer = TLSConnectAndEstablishTrust(
  363. EServerInfo.GetServerName(),
  364. NULL
  365. );
  366. if(hEServer != NULL)
  367. {
  368. dwStatus = TryLookupServer(
  369. hEServer,
  370. pszServerId,
  371. &szSetupId,
  372. &szDomainName,
  373. &szServerName,
  374. &dwErrCode
  375. );
  376. if(dwStatus == ERROR_SUCCESS && dwErrCode == ERROR_SUCCESS)
  377. {
  378. StringCbCopy(pszServerName,
  379. cbServerName,
  380. szServerName);
  381. MIDL_user_free(szSetupId);
  382. MIDL_user_free(szDomainName);
  383. MIDL_user_free(szServerName);
  384. }
  385. }
  386. }
  387. }
  388. if(hEServer != NULL)
  389. {
  390. TLSDisconnectFromServer(hEServer);
  391. }
  392. return dwStatus;
  393. }
  394. ///////////////////////////////////////////////////////////////
  395. DWORD
  396. TLSAnnounceServerToRemoteServerWithHandle(
  397. IN DWORD dwAnnounceType,
  398. IN TLS_HANDLE hHandle,
  399. IN LPTSTR pszLocalSetupId,
  400. IN LPTSTR pszLocalDomainName,
  401. IN LPTSTR pszLocalServerName,
  402. IN FILETIME* pftLocalLastShutdownTime
  403. )
  404. /*++
  405. Abstract:
  406. Announce to a license server that already connected.
  407. Parameters:
  408. dwAnnounceType : Announcement type, currently define are
  409. startup, and response.
  410. hHandle : Connection handle to remote server.
  411. pszLocalSetupId : Local server's setup ID.
  412. pszLocalDomainName : Local server's domain name.
  413. pszLocalServerName : Local server name.
  414. pftLocalLastShutdownTime : Pointer to FILETIME, local server's
  415. last shutdown time.
  416. Returns:
  417. ERROR_SUCCESS or error code.
  418. --*/
  419. {
  420. DWORD dwStatus;
  421. DWORD dwErrCode;
  422. TLServerInfo ServerInfo;
  423. if(hHandle == NULL)
  424. {
  425. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  426. return dwStatus;
  427. }
  428. //
  429. // First, try to register to server list manager.
  430. //
  431. dwStatus = TLSRegisterServerWithHandle(
  432. hHandle,
  433. &ServerInfo
  434. );
  435. if(dwStatus != ERROR_SUCCESS)
  436. {
  437. return dwStatus;
  438. }
  439. dwErrCode = LSERVER_E_LASTERROR + 1;
  440. //
  441. // RPC call to announce server
  442. //
  443. dwStatus = TLSAnnounceServer(
  444. hHandle,
  445. dwAnnounceType,
  446. pftLocalLastShutdownTime,
  447. pszLocalSetupId,
  448. (pszLocalDomainName) ? _TEXT("") : pszLocalDomainName,
  449. pszLocalServerName,
  450. &dwErrCode
  451. );
  452. if(dwStatus == ERROR_SUCCESS)
  453. {
  454. ServerInfo.m_dwPushAnnounceTimes++;
  455. //
  456. // Update how many time we have announce to
  457. // this server.
  458. TLSRegisterServerWithServerInfo(&ServerInfo);
  459. }
  460. if(dwStatus == ERROR_SUCCESS && dwErrCode >= LSERVER_ERROR_BASE)
  461. {
  462. TLSLogEvent(
  463. EVENTLOG_INFORMATION_TYPE,
  464. TLS_E_SERVERTOSERVER,
  465. TLS_E_UNEXPECTED_RETURN,
  466. ServerInfo.GetServerName(),
  467. (dwErrCode < LSERVER_E_LASTERROR) ? dwErrCode : LSERVER_ERROR_BASE
  468. );
  469. SetLastError(dwStatus = dwErrCode);
  470. }
  471. return dwStatus;
  472. }
  473. ///////////////////////////////////////////////////////////////
  474. DWORD
  475. TLSAnnounceServerToRemoteServer(
  476. IN DWORD dwAnnounceType,
  477. IN LPTSTR pszRemoteSetupId,
  478. IN LPTSTR pszRemoteDomainName,
  479. IN LPTSTR pszRemoteServerName,
  480. IN LPTSTR pszLocalSetupId,
  481. IN LPTSTR pszLocalDomainName,
  482. IN LPTSTR pszLocalServerName,
  483. IN FILETIME* pftLocalLastShutdownTime
  484. )
  485. /*++
  486. Abstract:
  487. Similar to TLSAnnounceServerToRemoteServerWithHandle() except
  488. we haven't have make any connection to this server yet.
  489. Parameter:
  490. dwAnnounceType : Announce type.
  491. pszRemoteSetupId : Remote server's setup ID.
  492. pszRemoteDomainName : Remote server's domain.
  493. pszRemoteServerName : Remote server's name.
  494. pszLocalSetupId : Local server setup ID.
  495. pszLocalDomainName : Local server's domain.
  496. pszLocalServerName : Local server's name.
  497. pftLocalLastShutdownTime : Local server last shutdown time.
  498. Returns:
  499. ERROR_SUCCESS or error code.
  500. --*/
  501. {
  502. TLServerInfo RemoteServer;
  503. DWORD dwStatus = ERROR_SUCCESS;
  504. DWORD dwErrCode = ERROR_SUCCESS;
  505. HANDLE hHandle = NULL;
  506. //
  507. // Always try to register with local list.
  508. //
  509. dwStatus = TLSRegisterServerWithName(
  510. pszRemoteSetupId,
  511. pszRemoteDomainName,
  512. pszRemoteServerName
  513. );
  514. if(dwStatus != ERROR_SUCCESS && dwStatus != TLS_E_DUPLICATE_RECORD )
  515. {
  516. return dwStatus;
  517. }
  518. //
  519. // Query again to make sure we have it in our server list.
  520. //
  521. dwStatus = TLSLookupRegisteredServer(
  522. pszRemoteSetupId,
  523. pszRemoteDomainName,
  524. pszRemoteServerName,
  525. &RemoteServer
  526. );
  527. if(dwStatus != ERROR_SUCCESS)
  528. {
  529. dwStatus = TLS_E_INTERNAL;
  530. TLSASSERT(FALSE);
  531. return dwStatus;
  532. }
  533. //
  534. // Establish trust with remote server.
  535. //
  536. hHandle = TLSConnectAndEstablishTrust(
  537. RemoteServer.GetServerName(),
  538. NULL
  539. );
  540. if(hHandle != NULL)
  541. {
  542. dwErrCode = LSERVER_E_LASTERROR + 1;
  543. //
  544. // Announce server
  545. //
  546. dwStatus = TLSAnnounceServer(
  547. hHandle,
  548. dwAnnounceType,
  549. pftLocalLastShutdownTime,
  550. pszLocalSetupId,
  551. (pszLocalDomainName) ? _TEXT("") : pszLocalDomainName,
  552. pszLocalServerName,
  553. &dwErrCode
  554. );
  555. if(dwStatus == ERROR_SUCCESS)
  556. {
  557. RemoteServer.m_dwPushAnnounceTimes++;
  558. // update announce time.
  559. TLSRegisterServerWithServerInfo(&RemoteServer);
  560. }
  561. if(dwStatus == ERROR_SUCCESS && dwErrCode >= LSERVER_ERROR_BASE)
  562. {
  563. TLSLogEvent(
  564. EVENTLOG_INFORMATION_TYPE,
  565. TLS_E_SERVERTOSERVER,
  566. TLS_E_UNEXPECTED_RETURN,
  567. RemoteServer.GetServerName(),
  568. (dwErrCode <= LSERVER_E_LASTERROR) ? dwErrCode : LSERVER_ERROR_BASE
  569. );
  570. SetLastError(dwStatus = dwErrCode);
  571. }
  572. }
  573. if(hHandle != NULL)
  574. {
  575. TLSDisconnectFromServer(hHandle);
  576. hHandle = NULL;
  577. }
  578. return dwStatus;
  579. }
  580. ///////////////////////////////////////////////////////////////
  581. TLS_HANDLE
  582. TLSConnectAndEstablishTrust(
  583. IN LPTSTR pszServerName,
  584. IN HANDLE hHandle
  585. )
  586. /*++
  587. Abstract:
  588. Connect and establish trust with remote server.
  589. Parameter:
  590. pszServerName : Name of the remote server if any.
  591. hHandle : Connection handle to this remote server if any.
  592. Returns:
  593. Connection handle to remote server or NULL if error.
  594. --*/
  595. {
  596. DWORD dwStatus = ERROR_SUCCESS;
  597. DWORD dwErrCode = ERROR_SUCCESS;
  598. BOOL bCleanupContextHandle = FALSE;
  599. if(hHandle == NULL && pszServerName == NULL)
  600. {
  601. SetLastError(ERROR_INVALID_PARAMETER);
  602. return NULL;
  603. }
  604. //
  605. // Use server name to connect
  606. //
  607. if(hHandle == NULL)
  608. {
  609. hHandle = TLSConnectToLsServer(pszServerName);
  610. // we make connection here so we need to cleanup
  611. bCleanupContextHandle = TRUE;
  612. if(hHandle == NULL)
  613. {
  614. dwStatus = GetLastError();
  615. }
  616. }
  617. if(hHandle != NULL)
  618. {
  619. //
  620. // establish trust with remote server
  621. //
  622. dwStatus = TLSEstablishTrustWithServer(
  623. hHandle,
  624. g_hCryptProv, // GLOBAL crypto provider
  625. CLIENT_TYPE_TLSERVER,
  626. &dwErrCode
  627. );
  628. if(dwStatus == ERROR_SUCCESS && dwErrCode >= LSERVER_ERROR_BASE)
  629. {
  630. //
  631. // BUGBUG : We still have lots of old license server running,
  632. // ignore this error code for now.
  633. //
  634. if(dwErrCode != LSERVER_E_ACCESS_DENIED)
  635. {
  636. LPTSTR szServer = NULL;
  637. DWORD dwCode;
  638. if(pszServerName == NULL)
  639. {
  640. dwStatus = TryGetServerName(
  641. hHandle,
  642. &szServer,
  643. &dwCode
  644. );
  645. if(dwStatus == RPC_S_OK && dwCode == ERROR_SUCCESS && szServer != NULL)
  646. {
  647. pszServerName = szServer;
  648. }
  649. }
  650. TLSLogEvent(
  651. EVENTLOG_ERROR_TYPE,
  652. TLS_E_SERVERTOSERVER,
  653. TLS_E_ESTABLISHTRUST,
  654. pszServerName,
  655. dwErrCode
  656. );
  657. if (NULL != szServer)
  658. {
  659. MIDL_user_free(szServer);
  660. }
  661. }
  662. SetLastError(dwStatus = dwErrCode);
  663. }
  664. if(dwStatus != ERROR_SUCCESS && hHandle != NULL && bCleanupContextHandle == TRUE)
  665. {
  666. // only cleanup if we make the connection in this routine.
  667. TLSDisconnectFromServer(hHandle);
  668. hHandle = NULL;
  669. }
  670. }
  671. return (dwStatus == ERROR_SUCCESS) ? hHandle : NULL;
  672. }
  673. ///////////////////////////////////////////////////////////////
  674. TLS_HANDLE
  675. TLSConnectToServerWithServerId(
  676. LPTSTR pszServerSetupId
  677. )
  678. /*++
  679. Abstract:
  680. Resolve a license server's unique ID to server name, then
  681. connect and establish trust relationship with the server.
  682. Parameter:
  683. pszServerSetupId : Server's unique ID.
  684. Returns:
  685. Server connection handle or NULL if error.
  686. --*/
  687. {
  688. TLS_HANDLE hHandle = NULL;
  689. TCHAR szServer[MAX_COMPUTERNAME_LENGTH+2];
  690. if(TLSLookupServerById(pszServerSetupId, szServer) != ERROR_SUCCESS)
  691. {
  692. //
  693. // server might not be available
  694. //
  695. SetLastError(TLS_E_SERVERLOOKUP);
  696. goto cleanup;
  697. }
  698. hHandle = TLSConnectAndEstablishTrust(szServer, NULL);
  699. cleanup:
  700. return hHandle;
  701. }
  702. ///////////////////////////////////////////////////////////////
  703. DWORD
  704. TLSRetrieveServerInfo(
  705. IN TLS_HANDLE hHandle,
  706. OUT PTLServerInfo pServerInfo
  707. )
  708. /*++
  709. Abstract:
  710. Retrieve server information from remote server.
  711. Parameter:
  712. hHandle : Connection handle to remote server.
  713. pServerInfo : Pointer to TLServerInfo to receive remote
  714. server's information.
  715. Return:
  716. ERROR_SUCCESS or error code.
  717. --*/
  718. {
  719. DWORD dwStatus;
  720. DWORD dwErrCode;
  721. DWORD dwBufSize;
  722. PBYTE pbServerPid = NULL;
  723. LPTSTR szServerName = NULL;
  724. LPTSTR szServerScope = NULL;
  725. if(hHandle == NULL)
  726. {
  727. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  728. return dwStatus;
  729. }
  730. //
  731. // Retrieve Server name.
  732. //
  733. dwStatus = TryGetServerName(
  734. hHandle,
  735. &szServerName,
  736. &dwErrCode
  737. );
  738. if(dwStatus != ERROR_SUCCESS || dwErrCode != ERROR_SUCCESS)
  739. {
  740. if(dwStatus == ERROR_SUCCESS)
  741. {
  742. dwStatus = dwErrCode;
  743. }
  744. goto cleanup;
  745. }
  746. else
  747. {
  748. StringCbCopy(
  749. pServerInfo->m_szServerName,
  750. sizeof(pServerInfo->m_szServerName),
  751. szServerName);
  752. MIDL_user_free(szServerName);
  753. }
  754. //
  755. // Retrieve server's scope, currently, server scope = domain/workgroup name
  756. // except in the case of enterprise server.
  757. //
  758. dwStatus = TryGetServerScope(
  759. hHandle,
  760. &szServerScope,
  761. &dwErrCode
  762. );
  763. if(dwStatus != ERROR_SUCCESS || dwErrCode != ERROR_SUCCESS)
  764. {
  765. if(dwStatus == ERROR_SUCCESS)
  766. {
  767. dwStatus = dwErrCode;
  768. }
  769. goto cleanup;
  770. }
  771. else
  772. {
  773. StringCbCopy(
  774. pServerInfo->m_szDomainName,
  775. sizeof(pServerInfo->m_szDomainName),
  776. szServerScope);
  777. MIDL_user_free(szServerScope);
  778. }
  779. //
  780. // Get Server's ID
  781. //
  782. dwStatus = TLSGetServerPID(
  783. hHandle,
  784. &dwBufSize,
  785. &pbServerPid,
  786. &dwErrCode
  787. );
  788. if(dwStatus != ERROR_SUCCESS || dwErrCode != ERROR_SUCCESS)
  789. {
  790. if(dwStatus == ERROR_SUCCESS)
  791. {
  792. dwStatus = dwErrCode;
  793. }
  794. goto cleanup;
  795. }
  796. if(pbServerPid == NULL || dwBufSize == 0)
  797. {
  798. // invalid return...
  799. // TLSASSERT(FALSE);
  800. dwStatus = ERROR_INVALID_DATA;
  801. goto cleanup;
  802. }
  803. StringCbCopyN(
  804. pServerInfo->m_szSetupId,
  805. sizeof(pServerInfo->m_szSetupId),
  806. (LPCTSTR)pbServerPid,
  807. min(sizeof(pServerInfo->m_szSetupId) - sizeof(TCHAR), dwBufSize)
  808. );
  809. midl_user_free(pbServerPid);
  810. //
  811. // retrieve server version information
  812. //
  813. dwStatus = TLSGetVersion(
  814. hHandle,
  815. &(pServerInfo->m_dwTLSVersion)
  816. );
  817. if(dwStatus == ERROR_SUCCESS)
  818. {
  819. DWORD dwMajorVersion;
  820. DWORD dwMinorVersion;
  821. dwMajorVersion = GET_SERVER_MAJOR_VERSION(pServerInfo->m_dwTLSVersion);
  822. dwMinorVersion = GET_SERVER_MINOR_VERSION(pServerInfo->m_dwTLSVersion);
  823. if(dwMajorVersion < GET_SERVER_MAJOR_VERSION(TLS_CURRENT_VERSION))
  824. {
  825. pServerInfo->m_dwCapability = TLSERVER_OLDVERSION;
  826. }
  827. else if( dwMajorVersion >= GET_SERVER_MAJOR_VERSION(TLS_CURRENT_VERSION) &&
  828. dwMinorVersion < GET_SERVER_MINOR_VERSION(TLS_CURRENT_VERSION) )
  829. {
  830. pServerInfo->m_dwCapability = TLSERVER_OLDVERSION;
  831. }
  832. // version 5.1 and above
  833. if(dwMajorVersion >= 0x5 && dwMinorVersion > 0)
  834. {
  835. pServerInfo->m_dwCapability |= TLSERVER_SUPPORTREPLICATION;
  836. }
  837. }
  838. cleanup:
  839. return dwStatus;
  840. }
  841. ///////////////////////////////////////////////////////////////
  842. DWORD
  843. TLSLookupAnyEnterpriseServer(
  844. OUT PTLServerInfo pServerInfo
  845. )
  846. /*++
  847. Abstract:
  848. Find any enterprise server in the registered server list.
  849. Parameter:
  850. pServerInfo - Pointer to TLServerInfo to receive enterprise server
  851. info.
  852. Returns:
  853. ERROR_SUCCESS or error code.
  854. --*/
  855. {
  856. TLServerInfo* pServer = NULL;
  857. BOOL bFound = FALSE;
  858. TLSBeginEnumKnownServerList();
  859. while(bFound == FALSE)
  860. {
  861. pServer = TLSGetNextKnownServer();
  862. if(pServer == NULL)
  863. {
  864. break;
  865. }
  866. if(pServer->IsServerEnterpriseServer() == TRUE)
  867. {
  868. *pServerInfo = *pServer;
  869. bFound = TRUE;
  870. }
  871. }
  872. TLSEndEnumKnownServerList();
  873. return (bFound == TRUE) ? ERROR_SUCCESS : TLS_E_RECORD_NOTFOUND;
  874. }
  875. ///////////////////////////////////////////////////////////////
  876. //
  877. // Various interface function to CTLServerMgr
  878. //
  879. ///////////////////////////////////////////////////////////////
  880. //------------------------------------------------------------
  881. //
  882. void
  883. TLSBeginEnumKnownServerList()
  884. {
  885. g_ServerMgr.ServerListEnumBegin();
  886. }
  887. //------------------------------------------------------------
  888. //
  889. const PTLServerInfo
  890. TLSGetNextKnownServer()
  891. {
  892. return g_ServerMgr.ServerListEnumNext();
  893. }
  894. //------------------------------------------------------------
  895. //
  896. void
  897. TLSEndEnumKnownServerList()
  898. {
  899. g_ServerMgr.ServerListEnumEnd();
  900. }
  901. //------------------------------------------------------------
  902. //
  903. DWORD
  904. TLSLookupServerById(
  905. IN LPTSTR pszServerSetupId,
  906. OUT LPTSTR pszServer
  907. )
  908. /*++
  909. Abstract:
  910. Loopup server name via server ID.
  911. Parameter:
  912. pszServerSetupId : remote server's setup ID.
  913. pszServer : name of the server, must be MAX_COMPUTERNAMELENGTH+1.
  914. Returns:
  915. ERROR_SUCCESS or error code.
  916. Remark:
  917. Internal call, no error checking on buffer side.
  918. ++*/
  919. {
  920. DWORD dwStatus = ERROR_SUCCESS;
  921. TLServerInfo ServerInfo;
  922. dwStatus = TLSLookupRegisteredServer(
  923. pszServerSetupId,
  924. NULL,
  925. NULL,
  926. &ServerInfo
  927. );
  928. if(dwStatus == ERROR_SUCCESS)
  929. {
  930. _tcscpy(pszServer, ServerInfo.GetServerName());
  931. }
  932. return dwStatus;
  933. }
  934. //------------------------------------------------------------
  935. //
  936. DWORD
  937. TLSRegisterServerWithName(
  938. IN LPTSTR pszSetupId,
  939. IN LPTSTR pszDomainName,
  940. IN LPTSTR pszServerName
  941. )
  942. /*++
  943. Abstract:
  944. Register a server with local server list manager.
  945. Parameter:
  946. pszSetupId : Remote server setup ID.
  947. pszDomainName : Remote server domain.
  948. pszServerName : Remote server name.
  949. Returns:
  950. ERROR_SUCCESS or error code.
  951. ++*/
  952. {
  953. TLS_HANDLE hHandle = NULL;
  954. TLServerInfo ServerInfo;
  955. DWORD dwStatus;
  956. //
  957. // Lookup server with local server list manager.
  958. //
  959. dwStatus = TLSLookupRegisteredServer(
  960. pszSetupId,
  961. pszDomainName,
  962. pszServerName,
  963. &ServerInfo
  964. );
  965. if( (dwStatus == ERROR_SUCCESS && ServerInfo.GetServerVersion() != 0) )
  966. {
  967. //
  968. // this server already registeted
  969. //
  970. return dwStatus;
  971. }
  972. if(dwStatus != ERROR_SUCCESS && dwStatus != TLS_E_RECORD_NOTFOUND)
  973. {
  974. // Error...
  975. return dwStatus;
  976. }
  977. dwStatus = ERROR_SUCCESS;
  978. //
  979. // retrieve remote server information
  980. //
  981. hHandle = TLSConnectAndEstablishTrust(
  982. pszServerName,
  983. NULL
  984. );
  985. if(hHandle != NULL)
  986. {
  987. dwStatus = TLSRetrieveServerInfo(
  988. hHandle,
  989. &ServerInfo
  990. );
  991. if(dwStatus == ERROR_SUCCESS)
  992. {
  993. dwStatus = TLSRegisterServerWithServerInfo(&ServerInfo);
  994. }
  995. }
  996. //
  997. // close conection
  998. //
  999. if(hHandle != NULL)
  1000. {
  1001. TLSDisconnectFromServer(hHandle);
  1002. }
  1003. return dwStatus;
  1004. }
  1005. //-----------------------------------------------------------
  1006. //
  1007. DWORD
  1008. TLSRegisterServerWithHandle(
  1009. IN TLS_HANDLE hHandle,
  1010. OUT PTLServerInfo pServerInfo
  1011. )
  1012. /*++
  1013. Abstract:
  1014. Register a remote server with local server list manager, this
  1015. differ from TLSRegisterServerWithName() in that it already has
  1016. make a connection to server.
  1017. Parameter:
  1018. hHandle - Connection handle to remote server.
  1019. pServerInfo - return remote server's information.
  1020. Returns:
  1021. ERROR_SUCCESS or error code.
  1022. ++*/
  1023. {
  1024. DWORD dwStatus;
  1025. TLS_HANDLE hTrustHandle;
  1026. TLServerInfo ServerInfo;
  1027. if(hHandle == NULL)
  1028. {
  1029. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1030. return dwStatus;
  1031. }
  1032. //
  1033. // Establish trust with remote server.
  1034. //
  1035. hTrustHandle = TLSConnectAndEstablishTrust(
  1036. NULL,
  1037. hHandle
  1038. );
  1039. if(hTrustHandle == NULL)
  1040. {
  1041. dwStatus = GetLastError();
  1042. return dwStatus;
  1043. }
  1044. //
  1045. // Retrieve remote server information.
  1046. //
  1047. dwStatus = TLSRetrieveServerInfo(
  1048. hHandle,
  1049. &ServerInfo
  1050. );
  1051. if(dwStatus == ERROR_SUCCESS)
  1052. {
  1053. if(pServerInfo != NULL)
  1054. {
  1055. *pServerInfo = ServerInfo;
  1056. }
  1057. dwStatus = TLSRegisterServerWithServerInfo(&ServerInfo);
  1058. }
  1059. return dwStatus;
  1060. }
  1061. //----------------------------------------------------------
  1062. DWORD
  1063. TLSRegisterServerWithServerInfo(
  1064. IN PTLServerInfo pServerInfo
  1065. )
  1066. /*++
  1067. Abstract:
  1068. Register a server with local server list manager.
  1069. Parameter:
  1070. pServerInfo : remote server information.
  1071. Returns:
  1072. ERROR_SUCCESS or error code.
  1073. ++*/
  1074. {
  1075. return g_ServerMgr.AddServerToList(pServerInfo);
  1076. }
  1077. //------------------------------------------------------------
  1078. //
  1079. DWORD
  1080. TLSLookupRegisteredServer(
  1081. IN LPTSTR pszSetupId,
  1082. IN LPTSTR pszDomainName,
  1083. IN LPTSTR pszServerName,
  1084. OUT PTLServerInfo pServerInfo
  1085. )
  1086. /*++
  1087. Abstract:
  1088. Look up and retrieve remote server information from local
  1089. server list manager.
  1090. Parameter:
  1091. pszSetupId : remote server setup ID if any.
  1092. pszDomainName : useless parameter, ignore
  1093. pszServerName : remote server name if any.
  1094. pServerInfo : Pointer to TLServerInfo to receive info. about
  1095. remote server.
  1096. Returns:
  1097. ERROR_SUCCESS or error code.
  1098. Remark:
  1099. Always try to resolve server with server's setup ID first
  1100. then server name.
  1101. ++*/
  1102. {
  1103. DWORD dwStatus;
  1104. if(pszSetupId == NULL && pszServerName == NULL)
  1105. {
  1106. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1107. return dwStatus;
  1108. }
  1109. if(pszSetupId)
  1110. {
  1111. dwStatus = g_ServerMgr.LookupBySetupId(
  1112. pszSetupId,
  1113. pServerInfo
  1114. );
  1115. }
  1116. else if(pszServerName)
  1117. {
  1118. dwStatus = g_ServerMgr.LookupByServerName(
  1119. pszServerName,
  1120. pServerInfo
  1121. );
  1122. }
  1123. return dwStatus;
  1124. }
  1125. ///////////////////////////////////////////////////////////////
  1126. //
  1127. // class CTLServerMgr
  1128. //
  1129. ///////////////////////////////////////////////////////////////
  1130. CTLServerMgr::CTLServerMgr()
  1131. {
  1132. }
  1133. //-----------------------------------------------------
  1134. CTLServerMgr::~CTLServerMgr()
  1135. {
  1136. PTLServerInfo pServer = NULL;
  1137. m_ReadWriteLock.Acquire(WRITER_LOCK);
  1138. //
  1139. // Disconnect from Server
  1140. //
  1141. for( MapIdToInfo::iterator it = m_Handles.begin();
  1142. it != m_Handles.end();
  1143. it++ )
  1144. {
  1145. pServer = (*it).second;
  1146. if(pServer != NULL)
  1147. {
  1148. delete pServer;
  1149. }
  1150. }
  1151. m_Handles.erase(m_Handles.begin(), m_Handles.end());
  1152. m_ReadWriteLock.Release(WRITER_LOCK);
  1153. }
  1154. //----------------------------------------------------
  1155. DWORD
  1156. CTLServerMgr::AddServerToList(
  1157. IN PTLServerInfo pServerInfo
  1158. )
  1159. /*++
  1160. Abstract:
  1161. Add a server into our server list.
  1162. Parameters:
  1163. pServerInfo - Information about remote server.
  1164. Returns:
  1165. ERROR_SUCCESS or error code.
  1166. --*/
  1167. {
  1168. DWORD dwStatus = ERROR_SUCCESS;
  1169. MapSetupIdToInfo findMap;
  1170. MapIdToInfo::iterator it;
  1171. if( pServerInfo == NULL )
  1172. {
  1173. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1174. return dwStatus;
  1175. }
  1176. findMap.pszSetupId = pServerInfo->GetServerId();
  1177. m_ReadWriteLock.Acquire(WRITER_LOCK);
  1178. it = m_Handles.find(findMap);
  1179. if(it == m_Handles.end())
  1180. {
  1181. PTLServerInfo pServer = NULL;
  1182. MapSetupIdToInfo serverMap;
  1183. // make a copy of input
  1184. pServer = new TLServerInfo;
  1185. *pServer = *pServerInfo;
  1186. serverMap.pszSetupId = pServer->GetServerId();
  1187. // Insert into our list
  1188. m_Handles[serverMap] = pServer;
  1189. }
  1190. else
  1191. {
  1192. dwStatus = TLS_E_DUPLICATE_RECORD;
  1193. // update information
  1194. *((*it).second) = *pServerInfo;
  1195. }
  1196. m_ReadWriteLock.Release(WRITER_LOCK);
  1197. return dwStatus;
  1198. }
  1199. //-----------------------------------------------------
  1200. DWORD
  1201. CTLServerMgr::AddServerToList(
  1202. IN LPCTSTR pszSetupId,
  1203. IN LPCTSTR pszDomainName,
  1204. IN LPCTSTR pszServerName
  1205. )
  1206. /*++
  1207. Abstract:
  1208. Add a server into our server list.
  1209. Parameter:
  1210. pszSetupId : remote server's ID.
  1211. pszDomainName : remote server's domain.
  1212. pszServerName : remote server name.
  1213. Returns:
  1214. ERROR_SUCCESS or error code.
  1215. ++*/
  1216. {
  1217. DWORD dwStatus = ERROR_SUCCESS;
  1218. if(pszSetupId == NULL || pszServerName == NULL)
  1219. {
  1220. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1221. return dwStatus;
  1222. }
  1223. PTLServerInfo pServerInfo = NULL;
  1224. MapSetupIdToInfo serverMap;
  1225. MapIdToInfo::iterator it;
  1226. serverMap.pszSetupId = pszSetupId;
  1227. m_ReadWriteLock.Acquire(WRITER_LOCK);
  1228. it = m_Handles.find(serverMap);
  1229. if(it == m_Handles.end())
  1230. {
  1231. pServerInfo = new TLServerInfo(pszSetupId, pszDomainName, pszServerName);
  1232. serverMap.pszSetupId = pServerInfo->GetServerId();
  1233. // Win64 compiler error
  1234. //m_Handles.insert( pair<MapSetupIdToInfo, PTLServerInfo>(serverMap, pServerHandle) );
  1235. // Insert into our list
  1236. m_Handles[serverMap] = pServerInfo;
  1237. }
  1238. else
  1239. {
  1240. if(lstrcmpi((*it).second->GetServerName(), pszServerName) != 0)
  1241. {
  1242. // update server name
  1243. (*it).second->UpdateServerName(pszServerName);
  1244. }
  1245. SetLastError(dwStatus = TLS_E_DUPLICATE_RECORD);
  1246. }
  1247. m_ReadWriteLock.Release(WRITER_LOCK);
  1248. return dwStatus;
  1249. }
  1250. //-----------------------------------------------------
  1251. DWORD
  1252. CTLServerMgr::LookupBySetupId(
  1253. IN LPCTSTR pszSetupId,
  1254. OUT PTLServerInfo pServerInfo
  1255. )
  1256. /*++
  1257. Abstract:
  1258. Lookup a server via its ID.
  1259. Parameters:
  1260. pszSetupId : Remote server setup ID.
  1261. pServerInfo : Pointer to TLServerInfo to receive
  1262. information about remote server.
  1263. Returns:
  1264. ERROR_SUCCESS or error code.
  1265. ++*/
  1266. {
  1267. DWORD dwStatus = ERROR_SUCCESS;
  1268. MapSetupIdToInfo serverMap;
  1269. MapIdToInfo::iterator it;
  1270. m_ReadWriteLock.Acquire(READER_LOCK);
  1271. serverMap.pszSetupId = pszSetupId;
  1272. it = m_Handles.find(serverMap);
  1273. if(it != m_Handles.end())
  1274. {
  1275. *pServerInfo = *((*it).second);
  1276. }
  1277. else
  1278. {
  1279. dwStatus = TLS_E_RECORD_NOTFOUND;
  1280. }
  1281. m_ReadWriteLock.Release(READER_LOCK);
  1282. return dwStatus;
  1283. }
  1284. //------------------------------------------------------
  1285. DWORD
  1286. CTLServerMgr::LookupByServerName(
  1287. IN LPCTSTR pszServerName,
  1288. OUT PTLServerInfo pServerInfo
  1289. )
  1290. /*++
  1291. Abstract:
  1292. Lookup server inforation via server name.
  1293. Parameters:
  1294. pszServerName : Name of server.
  1295. pServerInfo : Pointer to TLServerInfo to receive
  1296. information about remote server.
  1297. Returns:
  1298. ERROR_SUCCESS or error code.
  1299. Remark:
  1300. machine name might change from one boot to another,
  1301. it is not reliable to query by server name.
  1302. ++*/
  1303. {
  1304. DWORD dwStatus = ERROR_SUCCESS;
  1305. m_ReadWriteLock.Acquire(READER_LOCK);
  1306. for( MapIdToInfo::iterator it = m_Handles.begin();
  1307. it != m_Handles.end();
  1308. it++ )
  1309. {
  1310. if(_tcsicmp((*it).second->GetServerName(), pszServerName) == 0)
  1311. {
  1312. break;
  1313. }
  1314. }
  1315. if(it != m_Handles.end())
  1316. {
  1317. *pServerInfo = *((*it).second);
  1318. }
  1319. else
  1320. {
  1321. dwStatus = TLS_E_RECORD_NOTFOUND;
  1322. }
  1323. m_ReadWriteLock.Release(READER_LOCK);
  1324. return dwStatus;
  1325. }
  1326. //------------------------------------------------------
  1327. void
  1328. CTLServerMgr::ServerListEnumBegin()
  1329. /*++
  1330. Abstract:
  1331. Begin a enumeration on local server list.
  1332. Parameter:
  1333. None.
  1334. Returns:
  1335. None.
  1336. Remark:
  1337. This locks local server list into read only mode.
  1338. --*/
  1339. {
  1340. m_ReadWriteLock.Acquire(READER_LOCK);
  1341. enumIterator = m_Handles.begin();
  1342. }
  1343. //------------------------------------------------------
  1344. const PTLServerInfo
  1345. CTLServerMgr::ServerListEnumNext()
  1346. /*++
  1347. Abstract:
  1348. Retrieve next server in local server list.
  1349. Parameter:
  1350. None.
  1351. Returns:
  1352. Pointer to a server information.
  1353. Remark:
  1354. Must call ServerListEnumBegin().
  1355. --*/
  1356. {
  1357. PTLServerInfo pServerInfo = NULL;
  1358. if(enumIterator != m_Handles.end())
  1359. {
  1360. pServerInfo = (*enumIterator).second;
  1361. enumIterator++;
  1362. }
  1363. return pServerInfo;
  1364. }
  1365. //------------------------------------------------------
  1366. void
  1367. CTLServerMgr::ServerListEnumEnd()
  1368. /*++
  1369. Abstract:
  1370. End enumeration of local server list.
  1371. Parameter:
  1372. None.
  1373. Returns:
  1374. Pointer to a server information.
  1375. Remark:
  1376. Must call ServerListEnumBegin().
  1377. --*/
  1378. {
  1379. enumIterator = m_Handles.end();
  1380. m_ReadWriteLock.Release(READER_LOCK);
  1381. }