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.

4099 lines
142 KiB

  1. /****************************************************************************/
  2. // tssdjet.cpp
  3. //
  4. // Terminal Server Session Directory Jet RPC component code.
  5. //
  6. // Copyright (C) 2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <windows.h>
  9. #include <stdio.h>
  10. #include <process.h>
  11. #include <ole2.h>
  12. #include <objbase.h>
  13. #include <comdef.h>
  14. #include <winsta.h>
  15. #include <regapi.h>
  16. #include <winsock2.h>
  17. #include <Lm.h>
  18. #include <Security.h>
  19. #include <Iphlpapi.h>
  20. #include <wbemidl.h>
  21. #include <shlwapi.h>
  22. #include "tssdjet.h"
  23. #include "trace.h"
  24. #include "resource.h"
  25. #include "sdjetevent.h"
  26. #include "sdrpc.h"
  27. #pragma warning (push, 4)
  28. /****************************************************************************/
  29. // Defines
  30. /****************************************************************************/
  31. #define SECPACKAGELIST L"Kerberos,-NTLM"
  32. #define TSSD_FAILCOUNT_BEFORE_CLEARFLAG 4
  33. // Per bug 629057, use 1 min as the interval
  34. #define JET_RECOVERY_TIMEOUT 60*1000 // 1 min
  35. // If a network adapter is unconfigured it will have the following IP address
  36. #define UNCONFIGURED_IP_ADDRESS L"0.0.0.0"
  37. // Number of IP addresses for a machine
  38. #define SD_NUM_IP_ADDRESS 64
  39. #define LANATABLE_REG_NAME REG_CONTROL_TSERVER L"\\lanatable"
  40. #define LANAID_REG_VALUE_NAME L"LanaID"
  41. #define NETCARDS_REG_NAME L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"
  42. #define NETCARD_DESC_VALUE_NAME L"Description"
  43. #define NETCARD_SERVICENAME_VALUE_NAME L"ServiceName"
  44. /****************************************************************************/
  45. // Prototypes
  46. /****************************************************************************/
  47. INT_PTR CALLBACK CustomUIDlg(HWND, UINT, WPARAM, LPARAM);
  48. HRESULT GetSDIPList(WCHAR **pwszAddressList, DWORD *dwNumAddr, BOOL bIPAddress);
  49. HRESULT QueryNetworkAdapterAndIPs(HWND hComboBox);
  50. HRESULT GetNLBIP(LPWSTR * ppwszRetIP);
  51. HRESULT BuildLanaGUIDList(LPWSTR * pastrLanaGUIDList, DWORD *dwLanaGUIDCount);
  52. HRESULT GetLanAdapterGuidFromID(DWORD dwLanAdapterID, LPWSTR * ppszLanAdapterGUID);
  53. HRESULT GetAdapterServiceName(LPWSTR wszAdapterDesc, LPWSTR * ppwszServiceName);
  54. // User defined HResults
  55. #define S_ALL_ADAPTERS_SET MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_ITF, 0x200 + 1)
  56. /****************************************************************************/
  57. // Globals
  58. /****************************************************************************/
  59. extern HINSTANCE g_hInstance;
  60. DWORD (*g_updatesd)(DWORD); // Point to UpdateSessionDirectory in sessdir.cpp
  61. // The COM object counter (declared in server.cpp)
  62. extern long g_lObjects;
  63. // RPC binding string components - RPC over named pipes.
  64. const WCHAR *g_RPCUUID = L"aa177641-fc9b-41bd-80ff-f964a701596f";
  65. // From jetrpc.idl
  66. const WCHAR *g_RPCOptions = L"Security=Impersonation Dynamic False";
  67. const WCHAR *g_RPCProtocolSequence = L"ncacn_ip_tcp"; // RPC over TCP/IP
  68. const WCHAR *g_RPCRemoteEndpoint = L"\\pipe\\TSSD_Jet_RPC_Service";
  69. PSID g_pSDSid = NULL; //Sid for SD Computer
  70. /****************************************************************************/
  71. // TSSDJetGetLocalIPAddr
  72. //
  73. // Gets the local IP address of this machine. On success, returns 0. On
  74. // failure, returns a failure code from the function that failed.
  75. /****************************************************************************/
  76. DWORD TSSDJetGetLocalIPAddr(WCHAR *LocalIP)
  77. {
  78. unsigned char *tempaddr;
  79. char psServerNameA[64];
  80. struct hostent *hptr;
  81. int err, rc;
  82. rc = gethostname(psServerNameA, sizeof(psServerNameA));
  83. if (0 != rc) {
  84. err = WSAGetLastError();
  85. ERR((TB, "gethostname returns error %d\n", err));
  86. return err;
  87. }
  88. if ((hptr = gethostbyname(psServerNameA)) == 0) {
  89. err = WSAGetLastError();
  90. ERR((TB, "gethostbyname returns error %d\n", err));
  91. return err;
  92. }
  93. tempaddr = (unsigned char *)*(hptr->h_addr_list);
  94. wsprintf(LocalIP, L"%d.%d.%d.%d", tempaddr[0], tempaddr[1],
  95. tempaddr[2], tempaddr[3]);
  96. return 0;
  97. }
  98. /****************************************************************************/
  99. // MIDL_user_allocate
  100. // MIDL_user_free
  101. //
  102. // RPC-required allocation functions.
  103. /****************************************************************************/
  104. void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t Size)
  105. {
  106. return LocalAlloc(LMEM_FIXED, Size);
  107. }
  108. void __RPC_USER MIDL_user_free(void __RPC_FAR *p)
  109. {
  110. LocalFree(p);
  111. }
  112. //
  113. // PostSDJetErrorValueEvent
  114. //
  115. // Utility function used to create a system log wType event containing one
  116. // hex DWORD code value.
  117. void PostSDJetErrorValueEvent(unsigned EventCode, DWORD ErrVal, WORD wType)
  118. {
  119. HANDLE hLog;
  120. WCHAR hrString[128];
  121. PWSTR String = NULL;
  122. static DWORD numInstances = 0;
  123. //
  124. //count the numinstances of out of memory error, if this is more than
  125. //a specified number, we just won't log them
  126. //
  127. if( MY_STATUS_COMMITMENT_LIMIT == ErrVal )
  128. {
  129. if( numInstances > MAX_INSTANCE_MEMORYERR )
  130. return;
  131. //
  132. //if applicable, tell the user that we won't log any more of the out of memory errors
  133. //
  134. if( numInstances >= MAX_INSTANCE_MEMORYERR - 1 ) {
  135. wsprintfW(hrString, L"0x%X. This type of error will not be logged again to avoid eventlog fillup.", ErrVal);
  136. String = hrString;
  137. }
  138. numInstances++;
  139. }
  140. hLog = RegisterEventSource(NULL, L"TermServJet");
  141. if (hLog != NULL) {
  142. if( NULL == String ) {
  143. wsprintfW(hrString, L"0x%X", ErrVal);
  144. String = hrString;
  145. }
  146. ReportEvent(hLog, wType, 0, EventCode, NULL, 1, 0,
  147. (const WCHAR **)&String, NULL);
  148. DeregisterEventSource(hLog);
  149. }
  150. }
  151. // PostSDJetErrorMsgEvent
  152. //
  153. // Utility function used to create a system wType log event containing one
  154. // WCHAR msg.
  155. void PostSDJetErrorMsgEvent(unsigned EventCode, WCHAR *szMsg, WORD wType)
  156. {
  157. HANDLE hLog;
  158. hLog = RegisterEventSource(NULL, L"TermServJet");
  159. if (hLog != NULL) {
  160. ReportEvent(hLog, wType, 0, EventCode, NULL, 1, 0,
  161. (const WCHAR **)&szMsg, NULL);
  162. DeregisterEventSource(hLog);
  163. }
  164. }
  165. // Get the Sid of the SD Server
  166. BOOL LookUpSDComputerSID(WCHAR *SDComputerName)
  167. {
  168. WCHAR *DomainName = NULL;
  169. DWORD DomainNameSize = 0;
  170. DWORD SidSize = 0;
  171. SID_NAME_USE SidNameUse;
  172. BOOL rc = FALSE;
  173. DWORD Error;
  174. if (g_pSDSid) {
  175. LocalFree(g_pSDSid);
  176. g_pSDSid = NULL;
  177. }
  178. rc = LookupAccountName(NULL,
  179. SDComputerName,
  180. g_pSDSid,
  181. &SidSize,
  182. DomainName,
  183. &DomainNameSize,
  184. &SidNameUse);
  185. if (rc)
  186. goto HandleError;
  187. Error = GetLastError();
  188. if( ERROR_INSUFFICIENT_BUFFER != Error )
  189. goto HandleError;
  190. g_pSDSid = (PSID)LocalAlloc(LMEM_FIXED, SidSize);
  191. if (NULL == g_pSDSid) {
  192. goto HandleError;
  193. }
  194. DomainName = (LPWSTR)LocalAlloc(LMEM_FIXED,
  195. sizeof(WCHAR)*(1+DomainNameSize));
  196. if (NULL == DomainName) {
  197. goto HandleError;
  198. }
  199. rc = LookupAccountName(NULL,
  200. SDComputerName,
  201. g_pSDSid,
  202. &SidSize,
  203. DomainName,
  204. &DomainNameSize,
  205. &SidNameUse);
  206. if (!rc) {
  207. // fail
  208. ERR((TB, "Fail to get Sid for SD computer %S, err is %d\n", SDComputerName, GetLastError()));
  209. LocalFree(g_pSDSid);
  210. g_pSDSid = NULL;
  211. }
  212. LocalFree(DomainName);
  213. return rc;
  214. HandleError:
  215. rc = FALSE;
  216. return rc;
  217. }
  218. /****************************************************************************/
  219. // CTSSessionDirectory::CTSSessionDirectory
  220. // CTSSessionDirectory::~CTSSessionDirectory
  221. //
  222. // Constructor and destructor
  223. /****************************************************************************/
  224. CTSSessionDirectory::CTSSessionDirectory() :
  225. m_RefCount(0), m_hRPCBinding(NULL), m_hSDServerDown(NULL),
  226. m_hTerminateRecovery(NULL), m_hRecoveryThread(NULL), m_RecoveryTid(0),
  227. m_LockInitializationSuccessful(FALSE), m_SDIsUp(FALSE), m_Flags(0),
  228. m_hIPChange(NULL), m_NotifyIPChange(NULL), m_hInRepopulate(NULL), m_ConnectionEstablished(FALSE)
  229. {
  230. InterlockedIncrement(&g_lObjects);
  231. m_hCI = NULL;
  232. m_hRPCBinding = NULL;
  233. m_StoreServerName[0] = L'\0';
  234. m_LocalServerAddress[0] = L'\0';
  235. m_ClusterName[0] = L'\0';
  236. m_fEnabled = 0;
  237. m_tchProvider[0] = 0;
  238. m_tchDataSource[0] = 0;
  239. m_tchUserId[0] = 0;
  240. m_tchPassword[0] = 0;
  241. m_sr.Valid = FALSE;
  242. ZeroMemory(&m_OverLapped, sizeof(OVERLAPPED));
  243. // Recovery timeout should be configurable, but currently is not.
  244. // Time is in ms.
  245. m_RecoveryTimeout = JET_RECOVERY_TIMEOUT;
  246. m_bStartRPCListener = FALSE;
  247. if (InitializeSharedResource(&m_sr)) {
  248. m_LockInitializationSuccessful = TRUE;
  249. }
  250. else {
  251. ERR((TB, "Constructor: Failed to initialize shared resource"));
  252. }
  253. if( m_LockInitializationSuccessful == TRUE ) {
  254. // manual reset event in signal state initially
  255. m_hInRepopulate = CreateEvent( NULL, TRUE, TRUE, NULL );
  256. if( m_hInRepopulate == NULL ) {
  257. ERR((TB, "Init: Failed to create event for repopulate, err = "
  258. "%d", GetLastError()));
  259. m_LockInitializationSuccessful = FALSE;
  260. }
  261. }
  262. }
  263. CTSSessionDirectory::~CTSSessionDirectory()
  264. {
  265. RPC_STATUS RpcStatus;
  266. if (m_bStartRPCListener) {
  267. RpcStatus = RpcServerUnregisterIf(TSSDTOJETRPC_ServerIfHandle, NULL, NULL);
  268. if (RpcStatus != RPC_S_OK) {
  269. ERR((TB,"Error 0x%x in RpcServerUnregisterIf\n", RpcStatus));
  270. }
  271. }
  272. if (g_pSDSid) {
  273. LocalFree(g_pSDSid);
  274. g_pSDSid = NULL;
  275. }
  276. // Clean up.
  277. if (m_LockInitializationSuccessful) {
  278. Terminate();
  279. }
  280. if( m_hInRepopulate != NULL ) {
  281. CloseHandle( m_hInRepopulate );
  282. m_hInRepopulate = NULL;
  283. }
  284. if (m_sr.Valid)
  285. FreeSharedResource(&m_sr);
  286. // Decrement the global COM object counter.
  287. InterlockedDecrement(&g_lObjects);
  288. }
  289. /****************************************************************************/
  290. // CTSSessionDirectory::QueryInterface
  291. //
  292. // Standard COM IUnknown function.
  293. /****************************************************************************/
  294. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::QueryInterface(
  295. REFIID riid,
  296. void **ppv)
  297. {
  298. if (riid == IID_IUnknown) {
  299. *ppv = (LPVOID)(IUnknown *)(ITSSessionDirectory *)this;
  300. }
  301. else if (riid == IID_ITSSessionDirectory) {
  302. *ppv = (LPVOID)(ITSSessionDirectory *)this;
  303. }
  304. else if (riid == IID_IExtendServerSettings) {
  305. *ppv = (LPVOID)(IExtendServerSettings *)this;
  306. }
  307. else if (riid == IID_ITSSessionDirectoryEx) {
  308. *ppv = (LPVOID)(ITSSessionDirectoryEx *)this;
  309. }
  310. else {
  311. ERR((TB,"QI: Unknown interface"));
  312. *ppv = NULL;
  313. return E_NOINTERFACE;
  314. }
  315. ((IUnknown *)*ppv)->AddRef();
  316. return S_OK;
  317. }
  318. /****************************************************************************/
  319. // CTSSessionDirectory::AddRef
  320. //
  321. // Standard COM IUnknown function.
  322. /****************************************************************************/
  323. ULONG STDMETHODCALLTYPE CTSSessionDirectory::AddRef()
  324. {
  325. return InterlockedIncrement(&m_RefCount);
  326. }
  327. /****************************************************************************/
  328. // CTSSessionDirectory::Release
  329. //
  330. // Standard COM IUnknown function.
  331. /****************************************************************************/
  332. ULONG STDMETHODCALLTYPE CTSSessionDirectory::Release()
  333. {
  334. long lRef = InterlockedDecrement(&m_RefCount);
  335. if (lRef == 0)
  336. delete this;
  337. return lRef;
  338. }
  339. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::WaitForRepopulate(
  340. DWORD dwTimeOut
  341. )
  342. /*++
  343. --*/
  344. {
  345. DWORD dwStatus = ERROR_SUCCESS;
  346. ASSERT((m_hInRepopulate != NULL),(TB,"m_hInRepopulate is NULL"));
  347. if( m_hInRepopulate != NULL ) {
  348. dwStatus = WaitForSingleObject( m_hInRepopulate, dwTimeOut );
  349. #if DBG
  350. if( dwTimeOut > 0 && dwStatus != WAIT_OBJECT_0 ) {
  351. ERR((TB, "WARNING: WaitForRepopulate wait %d failed with %d", dwTimeOut, dwStatus));
  352. }
  353. #endif
  354. if( dwStatus == WAIT_OBJECT_0 ) {
  355. dwStatus = ERROR_SUCCESS;
  356. }
  357. else if( dwStatus == WAIT_TIMEOUT ) {
  358. dwStatus = ERROR_BUSY;
  359. }
  360. else if( dwStatus == WAIT_FAILED ) {
  361. dwStatus = GetLastError();
  362. }
  363. else {
  364. dwStatus = ERROR_INTERNAL_ERROR;
  365. }
  366. }
  367. else {
  368. dwStatus = ERROR_INTERNAL_ERROR;
  369. }
  370. return HRESULT_FROM_WIN32( dwStatus );
  371. }
  372. /****************************************************************************/
  373. // CTSSessionDirectory::Initialize
  374. //
  375. // ITSSessionDirectory function. Called soon after object instantiation to
  376. // initialize the directory. LocalServerAddress provides a text representation
  377. // of the local server's load balance IP address. This information should be
  378. // used as the server IP address in the session directory for client
  379. // redirection by other pool servers to this server. SessionDirectoryLocation,
  380. // SessionDirectoryClusterName, and SessionDirectoryAdditionalParams are
  381. // generic reg entries known to TermSrv which cover config info across any type
  382. // of session directory implementation. The contents of these strings are
  383. // designed to be parsed by the session directory providers.
  384. /****************************************************************************/
  385. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::Initialize(
  386. LPWSTR LocalServerAddress,
  387. LPWSTR StoreServerName,
  388. LPWSTR ClusterName,
  389. LPWSTR OpaqueSettings,
  390. DWORD Flags,
  391. DWORD (*repopfn)(),
  392. DWORD (*updatesd)(DWORD))
  393. {
  394. HRESULT hr = S_OK;
  395. DWORD Status;
  396. // Unreferenced parameter
  397. OpaqueSettings;
  398. if (m_LockInitializationSuccessful == FALSE) {
  399. hr = E_OUTOFMEMORY;
  400. goto ExitFunc;
  401. }
  402. if (!m_bStartRPCListener) {
  403. if (SDJETInitRPC())
  404. m_bStartRPCListener = TRUE;
  405. }
  406. ASSERT((LocalServerAddress != NULL),(TB,"Init: LocalServerAddr null!"));
  407. ASSERT((StoreServerName != NULL),(TB,"Init: StoreServerName null!"));
  408. ASSERT((ClusterName != NULL),(TB,"Init: ClusterName null!"));
  409. ASSERT((repopfn != NULL),(TB,"Init: repopfn null!"));
  410. ASSERT((updatesd != NULL),(TB,"Init: updatesd null!"));
  411. // Don't allow blank session directory server name.
  412. if (StoreServerName[0] == '\0') {
  413. hr = E_INVALIDARG;
  414. goto ExitFunc;
  415. }
  416. // Copy off the server address, store server, and cluster name for later
  417. // use.
  418. wcsncpy(m_StoreServerName, StoreServerName,
  419. sizeof(m_StoreServerName) / sizeof(WCHAR) - 1);
  420. m_StoreServerName[sizeof(m_StoreServerName) / sizeof(WCHAR) - 1] = L'\0';
  421. wcsncpy(m_LocalServerAddress, LocalServerAddress,
  422. sizeof(m_LocalServerAddress) / sizeof(WCHAR) - 1);
  423. m_LocalServerAddress[sizeof(m_LocalServerAddress) / sizeof(WCHAR) - 1] =
  424. L'\0';
  425. wcsncpy(m_ClusterName, ClusterName,
  426. sizeof(m_ClusterName) / sizeof(WCHAR) - 1);
  427. m_ClusterName[sizeof(m_ClusterName) / sizeof(WCHAR) - 1] = L'\0';
  428. m_Flags = Flags;
  429. m_repopfn = repopfn;
  430. g_updatesd = updatesd;
  431. TRC1((TB,"Initialize: Svr addr=%S, StoreSvrName=%S, ClusterName=%S, "
  432. "OpaqueSettings=%S, repopfn = %p",
  433. m_LocalServerAddress, m_StoreServerName, m_ClusterName,
  434. OpaqueSettings, repopfn));
  435. // Initialize recovery infrastructure
  436. // Initialize should not be called more than once.
  437. ASSERT((m_hSDServerDown == NULL),(TB, "Init: m_hSDServDown non-NULL!"));
  438. ASSERT((m_hRecoveryThread == NULL),(TB, "Init: m_hSDRecoveryThread "
  439. "non-NULL!"));
  440. ASSERT((m_hTerminateRecovery == NULL), (TB, "Init: m_hTerminateRecovery "
  441. "non-NULL!"));
  442. // we are initializing or re-initializing so connection to SD is down.
  443. SetSDConnectionDown();
  444. // Initially unsignaled
  445. m_hSDServerDown = CreateEvent(NULL, TRUE, FALSE, NULL);
  446. if (m_hSDServerDown == NULL) {
  447. ERR((TB, "Init: Failed to create event necessary for SD init, err = "
  448. "%d", GetLastError()));
  449. hr = E_FAIL;
  450. goto ExitFunc;
  451. }
  452. // Initially unsignaled, auto-reset.
  453. m_hTerminateRecovery = CreateEvent(NULL, FALSE, FALSE, NULL);
  454. if (m_hTerminateRecovery == NULL) {
  455. ERR((TB, "Init: Failed to create event necessary for SD init, err = "
  456. "%d", GetLastError()));
  457. hr = E_FAIL;
  458. goto ExitFunc;
  459. }
  460. // Initially unsignaled, auto-reset.
  461. m_hIPChange = CreateEvent(NULL, FALSE, FALSE, NULL);
  462. if (m_hIPChange == NULL) {
  463. ERR((TB, "Init: Failed to create event necessary for IP Change, err = "
  464. "%d", GetLastError()));
  465. hr = E_FAIL;
  466. goto ExitFunc;
  467. }
  468. m_OverLapped.hEvent = m_hIPChange;
  469. Status = NotifyAddrChange(&m_NotifyIPChange, &m_OverLapped);
  470. if (ERROR_IO_PENDING == Status ) {
  471. TRC1((TB, "Success: NotifyAddrChange returned IO_PENDING"));
  472. }
  473. else {
  474. ERR((TB, "Failure: NotifyAddrChange returned %d", Status));
  475. }
  476. // make sure event is at signal state initially.
  477. SetEvent( m_hInRepopulate );
  478. m_hRecoveryThread = _beginthreadex(NULL, 0, RecoveryThread, (void *) this,
  479. 0, &m_RecoveryTid);
  480. if (m_hRecoveryThread == NULL) {
  481. ERR((TB, "Init: Failed to create recovery thread, errno = %d", errno));
  482. hr = E_FAIL;
  483. goto ExitFunc;
  484. }
  485. // Start up the session directory (by faking server down).
  486. StartupSD();
  487. ExitFunc:
  488. return hr;
  489. }
  490. // Register RPC server on tssdjet, SD will call it when do recovering
  491. BOOL CTSSessionDirectory::SDJETInitRPC()
  492. {
  493. RPC_STATUS Status;
  494. RPC_BINDING_VECTOR *pBindingVector = 0;
  495. RPC_POLICY rpcpol = {sizeof(rpcpol), 0, 0};
  496. BOOL rc = FALSE;
  497. WCHAR *szPrincipalName = NULL;
  498. // Init the RPC server interface.
  499. Status = RpcServerUseProtseqEx(L"ncacn_ip_tcp", 3, 0, &rpcpol);
  500. if (Status != RPC_S_OK) {
  501. ERR((TB,"JETInitRPC: Error %d RpcUseProtseqEp on ncacn_ip_tcp",
  502. Status));
  503. goto PostRegisterService;
  504. }
  505. // Register our interface handle (found in sdrpc.h).
  506. Status = RpcServerRegisterIfEx(TSSDTOJETRPC_ServerIfHandle, NULL, NULL,
  507. 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, JetRpcAccessCheck);
  508. if (Status != RPC_S_OK) {
  509. ERR((TB,"JETInitRPC: Error %d RegIf", Status));
  510. goto PostRegisterService;
  511. }
  512. Status = RpcServerInqBindings(&pBindingVector);
  513. if (Status != RPC_S_OK) {
  514. ERR((TB,"JETInitRPC: Error %d InqBindings", Status));
  515. goto PostRegisterService;
  516. }
  517. Status = RpcEpRegister(TSSDTOJETRPC_ServerIfHandle, pBindingVector, 0, 0);
  518. if (Status != RPC_S_OK) {
  519. ERR((TB,"JETInitRPC: Error %d EpReg", Status));
  520. goto PostRegisterService;
  521. }
  522. Status = RpcServerInqDefaultPrincName(RPC_C_AUTHN_GSS_NEGOTIATE, &szPrincipalName);
  523. if (Status != RPC_S_OK) {
  524. ERR((TB,"JETInitRPC: Error %d ServerIngDefaultPrincName", Status));
  525. goto PostRegisterService;
  526. }
  527. Status = RpcServerRegisterAuthInfo(szPrincipalName, RPC_C_AUTHN_GSS_NEGOTIATE, NULL, NULL);
  528. RpcStringFree(&szPrincipalName);
  529. if (Status != RPC_S_OK) {
  530. ERR((TB,"JETInitRPC: Error %d RpcServerRegisterAuthInfo", Status));
  531. //PostSessDirErrorValueEvent(EVENT_FAIL_RPC_INIT_REGAUTHINFO, Status);
  532. goto PostRegisterService;
  533. }
  534. rc = TRUE;
  535. PostRegisterService:
  536. if (pBindingVector) {
  537. RpcBindingVectorFree(&pBindingVector);
  538. }
  539. return rc;
  540. }
  541. /****************************************************************************/
  542. // CTSSessionDirectory::Update
  543. //
  544. // ITSSessionDirectory function. Called whenever configuration settings change
  545. // on the terminal server. See Initialize for a description of the first four
  546. // arguments, the fifth, Result, is a flag of whether to request a refresh of
  547. // every session that should be in the session directory for this server after
  548. // this call completes.
  549. /****************************************************************************/
  550. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::Update(
  551. LPWSTR LocalServerAddress,
  552. LPWSTR StoreServerName,
  553. LPWSTR ClusterName,
  554. LPWSTR OpaqueSettings,
  555. DWORD Flags,
  556. BOOL ForceRejoin)
  557. {
  558. HRESULT hr = S_OK;
  559. ASSERT((LocalServerAddress != NULL),(TB,"Update: LocalServerAddr null!"));
  560. ASSERT((StoreServerName != NULL),(TB,"Update: StoreServerName null!"));
  561. ASSERT((ClusterName != NULL),(TB,"Update: ClusterName null!"));
  562. ASSERT((OpaqueSettings != NULL),(TB,"Update: OpaqueSettings null!"));
  563. // For update, we do not care about OpaqueSettings.
  564. // If the StoreServerName, ClusterName, LocalServerAddress or Flags has changed,
  565. // or ForceRejoin is TRUE
  566. // we terminate and then reinitialize.
  567. if ((_wcsnicmp(StoreServerName, m_StoreServerName, 64) != 0)
  568. || (_wcsnicmp(ClusterName, m_ClusterName, 64) != 0)
  569. || (wcsncmp(LocalServerAddress, m_LocalServerAddress, 64) != 0)
  570. || (Flags != m_Flags)
  571. || ForceRejoin) {
  572. // Terminate current connection.
  573. Terminate();
  574. // Initialize new connection.
  575. hr = Initialize(LocalServerAddress, StoreServerName, ClusterName,
  576. OpaqueSettings, Flags, m_repopfn, g_updatesd);
  577. }
  578. return hr;
  579. }
  580. /****************************************************************************/
  581. // CTSSessionDirectory::GetUserDisconnectedSessions
  582. //
  583. // Called to perform a query against the session directory, to provide the
  584. // list of disconnected sessions for the provided username and domain.
  585. // Returns zero or more TSSD_DisconnectedSessionInfo blocks in SessionBuf.
  586. // *pNumSessionsReturned receives the number of blocks.
  587. /****************************************************************************/
  588. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::GetUserDisconnectedSessions(
  589. LPWSTR UserName,
  590. LPWSTR Domain,
  591. DWORD __RPC_FAR *pNumSessionsReturned,
  592. TSSD_DisconnectedSessionInfo __RPC_FAR SessionBuf[
  593. TSSD_MaxDisconnectedSessions])
  594. {
  595. DWORD NumSessions = 0;
  596. HRESULT hr;
  597. unsigned i;
  598. unsigned long RpcException;
  599. TSSD_DiscSessInfo *adsi = NULL;
  600. TRC2((TB,"GetUserDisconnectedSessions"));
  601. ASSERT((pNumSessionsReturned != NULL),(TB,"NULL pNumSess"));
  602. ASSERT((SessionBuf != NULL),(TB,"NULL SessionBuf"));
  603. // Make the RPC call.
  604. if (EnterSDRpc()) {
  605. RpcTryExcept {
  606. hr = TSSDRpcGetUserDisconnectedSessions(m_hRPCBinding, &m_hCI,
  607. UserName, Domain, &NumSessions, &adsi);
  608. }
  609. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  610. RpcException = RpcExceptionCode();
  611. ERR((TB,"GetUserDisc: RPC Exception %d\n", RpcException));
  612. // In case RPC messed with us.
  613. m_hCI = NULL;
  614. NumSessions = 0;
  615. adsi = NULL;
  616. hr = E_FAIL;
  617. }
  618. RpcEndExcept
  619. if (SUCCEEDED(hr)) {
  620. TRC1((TB,"GetUserDisc: RPC call returned %u records", NumSessions));
  621. // Loop through and fill out the session records.
  622. for (i = 0; i < NumSessions; i++) {
  623. // ServerAddress
  624. wcsncpy(SessionBuf[i].ServerAddress, adsi[i].ServerAddress,
  625. sizeof(SessionBuf[i].ServerAddress) /
  626. sizeof(WCHAR) - 1);
  627. SessionBuf[i].ServerAddress[sizeof(
  628. SessionBuf[i].ServerAddress) /
  629. sizeof(WCHAR) - 1] = L'\0';
  630. // SessionId, TSProtocol
  631. SessionBuf[i].SessionID = adsi[i].SessionID;
  632. SessionBuf[i].TSProtocol = adsi[i].TSProtocol;
  633. // ApplicationType
  634. wcsncpy(SessionBuf[i].ApplicationType, adsi[i].AppType,
  635. sizeof(SessionBuf[i].ApplicationType) /
  636. sizeof(WCHAR) - 1);
  637. SessionBuf[i].ApplicationType[sizeof(SessionBuf[i].
  638. ApplicationType) / sizeof(WCHAR) - 1] = L'\0';
  639. // Resolutionwidth, ResolutionHeight, ColorDepth, CreateTime,
  640. // DisconnectionTime.
  641. SessionBuf[i].ResolutionWidth = adsi[i].ResolutionWidth;
  642. SessionBuf[i].ResolutionHeight = adsi[i].ResolutionHeight;
  643. SessionBuf[i].ColorDepth = adsi[i].ColorDepth;
  644. SessionBuf[i].CreateTime.dwLowDateTime = adsi[i].CreateTimeLow;
  645. SessionBuf[i].CreateTime.dwHighDateTime =
  646. adsi[i].CreateTimeHigh;
  647. SessionBuf[i].DisconnectionTime.dwLowDateTime =
  648. adsi[i].DisconnectTimeLow;
  649. SessionBuf[i].DisconnectionTime.dwHighDateTime =
  650. adsi[i].DisconnectTimeHigh;
  651. // Free the memory allocated by the server.
  652. MIDL_user_free(adsi[i].ServerAddress);
  653. MIDL_user_free(adsi[i].AppType);
  654. }
  655. }
  656. else {
  657. ERR((TB,"GetUserDisc: Failed RPC call, hr=0x%X", hr));
  658. NotifySDServerDown();
  659. }
  660. LeaveSDRpc();
  661. }
  662. else {
  663. ERR((TB,"GetUserDisc: Session Directory is unreachable"));
  664. hr = E_FAIL;
  665. }
  666. MIDL_user_free(adsi);
  667. *pNumSessionsReturned = NumSessions;
  668. return hr;
  669. }
  670. /****************************************************************************/
  671. // CTSSessionDirectory::NotifyCreateLocalSession
  672. //
  673. // ITSSessionDirectory function. Called when a session is created to add the
  674. // session to the session directory. Note that other interface functions
  675. // access the session directory by either the username/domain or the
  676. // session ID; the directory schema should take this into account for
  677. // performance optimization.
  678. /****************************************************************************/
  679. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyCreateLocalSession(
  680. TSSD_CreateSessionInfo __RPC_FAR *pCreateInfo)
  681. {
  682. HRESULT hr;
  683. unsigned long RpcException;
  684. BOOL bSDRPC = EnterSDRpc();
  685. BOOL bSDConnection = IsSDConnectionReady();
  686. // if EnterSDRPC() return FALSE and IsSDConnectionReady() return TRUE, that
  687. // indicate repopuating thread did not complete its task within 30 second
  688. // and this logon thread is running way ahead of it, we still need to report
  689. // logon to session directory, session directory will remove duplicate
  690. // entry.
  691. TRC2((TB,"NotifyCreateLocalSession, SessID=%u", pCreateInfo->SessionID));
  692. ASSERT((pCreateInfo != NULL),(TB,"NotifyCreate: NULL CreateInfo"));
  693. #if DBG
  694. if( bSDConnection == TRUE && bSDRPC == FALSE ) {
  695. TRC2((TB,"NotifyCreateLocalSession, SessID=%u, logon thread is way ahead of repopulating thread", pCreateInfo->SessionID));
  696. }
  697. #endif
  698. // Make the RPC call.
  699. if (bSDConnection) {
  700. // Make the RPC call.
  701. RpcTryExcept {
  702. // Make the call.
  703. hr = TSSDRpcCreateSession(m_hRPCBinding, &m_hCI,
  704. pCreateInfo->UserName,
  705. pCreateInfo->Domain, pCreateInfo->SessionID,
  706. pCreateInfo->TSProtocol, pCreateInfo->ApplicationType,
  707. pCreateInfo->ResolutionWidth, pCreateInfo->ResolutionHeight,
  708. pCreateInfo->ColorDepth,
  709. pCreateInfo->CreateTime.dwLowDateTime,
  710. pCreateInfo->CreateTime.dwHighDateTime);
  711. }
  712. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  713. RpcException = RpcExceptionCode();
  714. ERR((TB,"NotifyCreate: RPC Exception %d\n", RpcException));
  715. hr = E_FAIL;
  716. }
  717. RpcEndExcept
  718. // we only notify SD server down when EnterSDRpc() return TRUE,
  719. if (FAILED(hr) && bSDRPC) {
  720. ERR((TB,"NotifyCreate: Failed RPC call, hr=0x%X", hr));
  721. NotifySDServerDown();
  722. }
  723. }
  724. if( bSDRPC ) {
  725. LeaveSDRpc();
  726. }
  727. if( !bSDRPC && !bSDConnection ) {
  728. ERR((TB,"NotifyCreate: Session directory is unreachable"));
  729. hr = E_FAIL;
  730. }
  731. return hr;
  732. }
  733. /****************************************************************************/
  734. // CTSSessionDirectory::NotifyDestroyLocalSession
  735. //
  736. // ITSSessionDirectory function. Removes a session from the session database.
  737. /****************************************************************************/
  738. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyDestroyLocalSession(
  739. DWORD SessionID)
  740. {
  741. HRESULT hr;
  742. unsigned long RpcException;
  743. TRC2((TB,"NotifyDestroyLocalSession, SessionID=%u", SessionID));
  744. // Make the RPC call.
  745. if (EnterSDRpc()) {
  746. RpcTryExcept {
  747. // Make the call.
  748. hr = TSSDRpcDeleteSession(m_hRPCBinding, &m_hCI, SessionID);
  749. }
  750. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  751. RpcException = RpcExceptionCode();
  752. ERR((TB,"NotifyDestroy: RPC Exception %d\n", RpcException));
  753. hr = E_FAIL;
  754. }
  755. RpcEndExcept
  756. if (FAILED(hr)) {
  757. ERR((TB,"NotifyDestroy: Failed RPC call, hr=0x%X", hr));
  758. NotifySDServerDown();
  759. }
  760. LeaveSDRpc();
  761. }
  762. else {
  763. ERR((TB,"NotifyDestroy: Session directory is unreachable"));
  764. hr = E_FAIL;
  765. }
  766. return hr;
  767. }
  768. /****************************************************************************/
  769. // CTSSessionDirectory::NotifyDisconnectLocalSession
  770. //
  771. // ITSSessionDirectory function. Changes the state of an existing session to
  772. // disconnected. The provided time should be returned in disconnected session
  773. // queries performed by any machine in the server pool.
  774. /****************************************************************************/
  775. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyDisconnectLocalSession(
  776. DWORD SessionID,
  777. FILETIME DiscTime)
  778. {
  779. HRESULT hr;
  780. unsigned long RpcException;
  781. TRC2((TB,"NotifyDisconnectLocalSession, SessionID=%u", SessionID));
  782. // Make the RPC call.
  783. if (EnterSDRpc()) {
  784. RpcTryExcept {
  785. // Make the call.
  786. hr = TSSDRpcSetSessionDisconnected(m_hRPCBinding, &m_hCI, SessionID,
  787. DiscTime.dwLowDateTime, DiscTime.dwHighDateTime);
  788. }
  789. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  790. RpcException = RpcExceptionCode();
  791. ERR((TB,"NotifyDisc: RPC Exception %d\n", RpcException));
  792. hr = E_FAIL;
  793. }
  794. RpcEndExcept
  795. if (FAILED(hr)) {
  796. ERR((TB,"NotifyDisc: RPC call failed, hr=0x%X", hr));
  797. NotifySDServerDown();
  798. }
  799. LeaveSDRpc();
  800. }
  801. else {
  802. ERR((TB,"NotifyDisc: Session directory is unreachable"));
  803. hr = E_FAIL;
  804. }
  805. return hr;
  806. }
  807. /****************************************************************************/
  808. // CTSSessionDirectory::NotifyReconnectLocalSession
  809. //
  810. // ITSSessionDirectory function. Changes the state of an existing session
  811. // from disconnected to connected.
  812. /****************************************************************************/
  813. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyReconnectLocalSession(
  814. TSSD_ReconnectSessionInfo __RPC_FAR *pReconnInfo)
  815. {
  816. HRESULT hr;
  817. unsigned long RpcException;
  818. TRC2((TB,"NotifyReconnectLocalSession, SessionID=%u",
  819. pReconnInfo->SessionID));
  820. // Make the RPC call.
  821. if (EnterSDRpc()) {
  822. RpcTryExcept {
  823. // Make the call.
  824. hr = TSSDRpcSetSessionReconnected(m_hRPCBinding, &m_hCI,
  825. pReconnInfo->SessionID, pReconnInfo->TSProtocol,
  826. pReconnInfo->ResolutionWidth, pReconnInfo->ResolutionHeight,
  827. pReconnInfo->ColorDepth);
  828. }
  829. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  830. RpcException = RpcExceptionCode();
  831. ERR((TB,"NotifyReconn: RPC Exception %d\n", RpcException));
  832. hr = E_FAIL;
  833. }
  834. RpcEndExcept
  835. if (FAILED(hr)) {
  836. ERR((TB,"NotifyReconn: RPC call failed, hr=0x%X", hr));
  837. NotifySDServerDown();
  838. }
  839. LeaveSDRpc();
  840. }
  841. else {
  842. ERR((TB,"NotifyReconn: Session directory is unreachable"));
  843. hr = E_FAIL;
  844. }
  845. return hr;
  846. }
  847. /****************************************************************************/
  848. // CTSSessionDirectory::NotifyReconnectPending
  849. //
  850. // ITSSessionDirectory function. Informs session directory that a reconnect
  851. // is pending soon because of a revectoring. Used by DIS to determine
  852. // when a server might have gone down. (DIS is the Directory Integrity
  853. // Service, which runs on the machine with the session directory.)
  854. //
  855. // This is a two-phase procedure--we first check the fields, and then we
  856. // add the timestamp only if there is no outstanding timestamp already (i.e.,
  857. // the two Almost-In-Time fields are 0). This prevents constant revectoring
  858. // from updating the timestamp fields, which would prevent the DIS from
  859. // figuring out that a server is down.
  860. //
  861. // These two steps are done in the stored procedure to make the operation
  862. // atomic.
  863. /****************************************************************************/
  864. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::NotifyReconnectPending(
  865. WCHAR *ServerName)
  866. {
  867. HRESULT hr;
  868. unsigned long RpcException;
  869. FILETIME ft;
  870. SYSTEMTIME st;
  871. TRC2((TB,"NotifyReconnectPending"));
  872. ASSERT((ServerName != NULL),(TB,"NotifyReconnectPending: NULL ServerName"));
  873. // Get the current system time.
  874. GetSystemTime(&st);
  875. SystemTimeToFileTime(&st, &ft);
  876. // Make the RPC call.
  877. if (EnterSDRpc()) {
  878. RpcTryExcept {
  879. // Make the call.
  880. hr = TSSDRpcSetServerReconnectPending(m_hRPCBinding, ServerName,
  881. ft.dwLowDateTime, ft.dwHighDateTime);
  882. }
  883. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  884. RpcException = RpcExceptionCode();
  885. ERR((TB,"NotifyReconnPending: RPC Exception %d\n", RpcException));
  886. hr = E_FAIL;
  887. }
  888. RpcEndExcept
  889. if (FAILED(hr)) {
  890. ERR((TB,"NotifyReconnPending: RPC call failed, hr=0x%X", hr));
  891. NotifySDServerDown();
  892. }
  893. LeaveSDRpc();
  894. }
  895. else {
  896. ERR((TB,"NotifyReconnPending: Session directory is unreachable"));
  897. hr = E_FAIL;
  898. }
  899. return hr;
  900. }
  901. /****************************************************************************/
  902. // CTSSessionDirectory::Repopulate
  903. //
  904. // This function is called by the recovery thread, and repopulates the session
  905. // directory with all sessions.
  906. //
  907. // Arguments: WinStationCount - # of winstations to repopulate
  908. // rsi - array of TSSD_RepopulateSessionInfo structs.
  909. //
  910. // Return value: HRESULT
  911. /****************************************************************************/
  912. #if DBG
  913. #define MAX_REPOPULATE_SESSION 3
  914. #else
  915. #define MAX_REPOPULATE_SESSION 25
  916. #endif
  917. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::Repopulate(DWORD WinStationCount,
  918. TSSD_RepopulateSessionInfo *rsi)
  919. {
  920. HRESULT hr = S_OK;
  921. unsigned long RpcException;
  922. DWORD dwNumSessionLeft = WinStationCount;
  923. DWORD dwSessionsToRepopulate;
  924. DWORD i;
  925. ASSERT(((rsi != NULL) || (WinStationCount == 0)),(TB,"Repopulate: NULL "
  926. "rsi!"));
  927. RpcTryExcept {
  928. for(i = 0 ; dwNumSessionLeft > 0 && SUCCEEDED(hr); i++) {
  929. dwSessionsToRepopulate = (dwNumSessionLeft > MAX_REPOPULATE_SESSION) ? MAX_REPOPULATE_SESSION : dwNumSessionLeft;
  930. hr = TSSDRpcRepopulateAllSessions(m_hRPCBinding, &m_hCI,
  931. dwSessionsToRepopulate,
  932. (TSSD_RepopInfo *) (rsi + i * MAX_REPOPULATE_SESSION) );
  933. dwNumSessionLeft -= dwSessionsToRepopulate;
  934. }
  935. if (FAILED(hr)) {
  936. ERR((TB, "Repop: RPC call failed, hr = 0x%X", hr));
  937. }
  938. }
  939. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  940. RpcException = RpcExceptionCode();
  941. ERR((TB, "Repop: RPC Exception %d\n", RpcException));
  942. hr = E_FAIL;
  943. }
  944. RpcEndExcept
  945. return hr;
  946. }
  947. /****************************************************************************/
  948. // Plug-in UI interface for TSCC
  949. /****************************************************************************/
  950. /****************************************************************************/
  951. // describes the name of this entry in server settings
  952. /****************************************************************************/
  953. STDMETHODIMP CTSSessionDirectory::GetAttributeName(
  954. /* out */ WCHAR *pwszAttribName)
  955. {
  956. TCHAR szAN[256];
  957. ASSERT((pwszAttribName != NULL),(TB,"NULL attrib ptr"));
  958. LoadString(g_hInstance, IDS_ATTRIBUTE_NAME, szAN, sizeof(szAN) /
  959. sizeof(TCHAR));
  960. lstrcpy(pwszAttribName, szAN);
  961. return S_OK;
  962. }
  963. /****************************************************************************/
  964. // for this component the attribute value indicates whether it is enabled
  965. /****************************************************************************/
  966. STDMETHODIMP CTSSessionDirectory::GetDisplayableValueName(
  967. /* out */WCHAR *pwszAttribValueName)
  968. {
  969. TCHAR szAvn[256];
  970. ASSERT((pwszAttribValueName != NULL),(TB,"NULL attrib ptr"));
  971. POLICY_TS_MACHINE gpolicy;
  972. RegGetMachinePolicy(&gpolicy);
  973. if (gpolicy.fPolicySessionDirectoryActive)
  974. m_fEnabled = gpolicy.SessionDirectoryActive;
  975. else
  976. m_fEnabled = IsSessionDirectoryEnabled();
  977. if (m_fEnabled)
  978. {
  979. LoadString(g_hInstance, IDS_ENABLE, szAvn, sizeof(szAvn) /
  980. sizeof(TCHAR));
  981. }
  982. else
  983. {
  984. LoadString(g_hInstance, IDS_DISABLE, szAvn, sizeof(szAvn) /
  985. sizeof(TCHAR));
  986. }
  987. lstrcpy(pwszAttribValueName, szAvn);
  988. return S_OK;
  989. }
  990. /****************************************************************************/
  991. // Provides custom UI
  992. /****************************************************************************/
  993. STDMETHODIMP CTSSessionDirectory::InvokeUI(/* in */ HWND hParent, /*out*/
  994. PDWORD pdwStatus)
  995. {
  996. WSADATA wsaData;
  997. if (WSAStartup(0x202, &wsaData) == 0)
  998. {
  999. INT_PTR iRet = DialogBoxParam(g_hInstance,
  1000. MAKEINTRESOURCE(IDD_DIALOG_SDS),
  1001. hParent,
  1002. CustomUIDlg,
  1003. (LPARAM)this
  1004. );
  1005. // TRC1((TB,"DialogBox returned 0x%x", iRet));
  1006. // TRC1((TB,"Extended error = %lx", GetLastError()));
  1007. *pdwStatus = (DWORD)iRet;
  1008. WSACleanup();
  1009. }
  1010. else
  1011. {
  1012. *pdwStatus = WSAGetLastError();
  1013. TRC1((TB,"WSAStartup failed with 0x%x", *pdwStatus));
  1014. ErrorMessage(hParent, IDS_ERROR_TEXT3, *pdwStatus);
  1015. return E_FAIL;
  1016. }
  1017. return S_OK;
  1018. }
  1019. /****************************************************************************/
  1020. // Custom menu items -- must be freed by LocalFree
  1021. // this is called everytime the user right clicks the listitem
  1022. // so you can alter the settings (i.e. enable to disable and vice versa)
  1023. /****************************************************************************/
  1024. STDMETHODIMP CTSSessionDirectory::GetMenuItems(
  1025. /* out */ int *pcbItems,
  1026. /* out */ PMENUEXTENSION *pMex)
  1027. {
  1028. ASSERT((pcbItems != NULL),(TB,"NULL items ptr"));
  1029. *pcbItems = 2;
  1030. *pMex = (PMENUEXTENSION)LocalAlloc(LMEM_FIXED, *pcbItems *
  1031. sizeof(MENUEXTENSION));
  1032. if (*pMex != NULL)
  1033. {
  1034. LoadString(g_hInstance, IDS_PROPERTIES, (*pMex)[0].MenuItemName,
  1035. sizeof((*pMex)[0].MenuItemName) / sizeof(WCHAR));
  1036. LoadString(g_hInstance, IDS_DESCRIP_PROPS, (*pMex)[0].StatusBarText,
  1037. sizeof((*pMex)[0].StatusBarText) / sizeof(WCHAR));
  1038. (*pMex)[0].fFlags = 0;
  1039. // menu items id -- this id will be passed back to you in ExecMenuCmd
  1040. (*pMex)[0].cmd = IDM_MENU_PROPS;
  1041. // load string to display enable or disable
  1042. (*pMex)[1].fFlags = 0;
  1043. if (!m_fEnabled)
  1044. {
  1045. LoadString(g_hInstance, IDS_ENABLE, (*pMex)[1].MenuItemName,
  1046. sizeof((*pMex)[1].MenuItemName) / sizeof(WCHAR));
  1047. // Disable this menu item if the store server name is empty
  1048. if (CheckIfSessionDirectoryNameEmpty(REG_TS_CLUSTER_STORESERVERNAME)) {
  1049. //Clear the last 2 bits since MF_GRAYED is
  1050. //incompatible with MF_DISABLED
  1051. (*pMex)[1].fFlags &= 0xFFFFFFFCL;
  1052. (*pMex)[1].fFlags |= MF_GRAYED;
  1053. }
  1054. }
  1055. else
  1056. {
  1057. LoadString(g_hInstance, IDS_DISABLE, (*pMex)[1].MenuItemName,
  1058. sizeof((*pMex)[1].MenuItemName) / sizeof(WCHAR));
  1059. }
  1060. // acquire the description text for menu item
  1061. LoadString(g_hInstance, IDS_DESCRIP_ENABLE, (*pMex)[1].StatusBarText,
  1062. sizeof((*pMex)[1].StatusBarText) / sizeof(WCHAR));
  1063. // menu items id -- this id will be passed back to you in ExecMenuCmd
  1064. (*pMex)[1].cmd = IDM_MENU_ENABLE;
  1065. return S_OK;
  1066. }
  1067. else
  1068. {
  1069. return E_OUTOFMEMORY;
  1070. }
  1071. }
  1072. /****************************************************************************/
  1073. // When the user selects a menu item the cmd id is passed to this component.
  1074. // the provider (which is us)
  1075. /****************************************************************************/
  1076. STDMETHODIMP CTSSessionDirectory::ExecMenuCmd(
  1077. /* in */ UINT cmd,
  1078. /* in */ HWND hParent,
  1079. /* out*/ PDWORD pdwStatus)
  1080. {
  1081. WSADATA wsaData;
  1082. switch (cmd) {
  1083. case IDM_MENU_ENABLE:
  1084. m_fEnabled = m_fEnabled ? 0 : 1;
  1085. TRC1((TB,"%ws was selected", m_fEnabled ? L"Disable" : L"Enable"));
  1086. if (SetSessionDirectoryEnabledState(m_fEnabled) == ERROR_SUCCESS)
  1087. {
  1088. *pdwStatus = UPDATE_TERMSRV_SESSDIR;
  1089. }
  1090. break;
  1091. case IDM_MENU_PROPS:
  1092. if (WSAStartup(0x202, &wsaData) == 0)
  1093. {
  1094. INT_PTR iRet = DialogBoxParam(g_hInstance,
  1095. MAKEINTRESOURCE(IDD_DIALOG_SDS),
  1096. hParent,
  1097. CustomUIDlg,
  1098. (LPARAM)this);
  1099. *pdwStatus = (DWORD)iRet;
  1100. WSACleanup();
  1101. }
  1102. else
  1103. {
  1104. *pdwStatus = WSAGetLastError();
  1105. TRC1((TB,"WSAStartup failed with 0x%x", *pdwStatus));
  1106. ErrorMessage(hParent, IDS_ERROR_TEXT3, *pdwStatus);
  1107. return E_FAIL;
  1108. }
  1109. }
  1110. return S_OK;
  1111. }
  1112. /****************************************************************************/
  1113. // Tscc provides a default help menu item, when selected this method is called
  1114. // if we want tscc to handle (or provide) help return any value other than zero
  1115. // for those u can't follow logic return zero if you're handling help.
  1116. /****************************************************************************/
  1117. STDMETHODIMP CTSSessionDirectory::OnHelp(/* out */ int *piRet)
  1118. {
  1119. ASSERT((piRet != NULL),(TB,"NULL ret ptr"));
  1120. *piRet = 0;
  1121. return S_OK;
  1122. }
  1123. /****************************************************************************/
  1124. // CheckSessionDirectorySetting returns a bool
  1125. /****************************************************************************/
  1126. BOOL CTSSessionDirectory::CheckSessionDirectorySetting(WCHAR *Setting)
  1127. {
  1128. LONG lRet;
  1129. HKEY hKey;
  1130. DWORD dwEnabled = 0;
  1131. DWORD dwSize = sizeof(DWORD);
  1132. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1133. REG_CONTROL_TSERVER,
  1134. 0,
  1135. KEY_READ,
  1136. &hKey);
  1137. if (lRet == ERROR_SUCCESS)
  1138. {
  1139. lRet = RegQueryValueEx(hKey,
  1140. Setting,
  1141. NULL,
  1142. NULL,
  1143. (LPBYTE)&dwEnabled,
  1144. &dwSize);
  1145. RegCloseKey(hKey);
  1146. }
  1147. return (BOOL)dwEnabled;
  1148. }
  1149. /****************************************************************************/
  1150. // CheckSessionDirectorySetting returns a bool
  1151. // returns TRUE if this registry value is empty
  1152. /****************************************************************************/
  1153. BOOL CTSSessionDirectory::CheckIfSessionDirectoryNameEmpty(WCHAR *Setting)
  1154. {
  1155. LONG lRet;
  1156. HKEY hKey;
  1157. WCHAR Names[SDNAMELENGTH];
  1158. DWORD dwSize = sizeof(Names);
  1159. BOOL rc = TRUE;
  1160. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1161. REG_TS_CLUSTERSETTINGS,
  1162. 0,
  1163. KEY_READ,
  1164. &hKey);
  1165. if (lRet == ERROR_SUCCESS)
  1166. {
  1167. lRet = RegQueryValueEx(hKey,
  1168. Setting,
  1169. NULL,
  1170. NULL,
  1171. (BYTE *)Names,
  1172. &dwSize);
  1173. if (lRet == ERROR_SUCCESS) {
  1174. if (wcslen(Names) != 0) {
  1175. rc = FALSE;
  1176. }
  1177. }
  1178. RegCloseKey(hKey);
  1179. }
  1180. return rc;
  1181. }
  1182. /****************************************************************************/
  1183. // IsSessionDirectoryEnabled returns a bool
  1184. /****************************************************************************/
  1185. BOOL CTSSessionDirectory::IsSessionDirectoryEnabled()
  1186. {
  1187. return CheckSessionDirectorySetting(REG_TS_SESSDIRACTIVE);
  1188. }
  1189. /****************************************************************************/
  1190. // IsSessionDirectoryEnabled returns a bool
  1191. /****************************************************************************/
  1192. BOOL CTSSessionDirectory::IsSessionDirectoryExposeServerIPEnabled()
  1193. {
  1194. return CheckSessionDirectorySetting(REG_TS_SESSDIR_EXPOSE_SERVER_ADDR);
  1195. }
  1196. /****************************************************************************/
  1197. // SetSessionDirectoryState - sets "Setting" regkey to bVal
  1198. /****************************************************************************/
  1199. DWORD CTSSessionDirectory::SetSessionDirectoryState(WCHAR *Setting, BOOL bVal)
  1200. {
  1201. LONG lRet;
  1202. HKEY hKey;
  1203. DWORD dwSize = sizeof(DWORD);
  1204. lRet = RegOpenKeyEx(
  1205. HKEY_LOCAL_MACHINE,
  1206. REG_CONTROL_TSERVER,
  1207. 0,
  1208. KEY_WRITE,
  1209. &hKey);
  1210. if (lRet == ERROR_SUCCESS)
  1211. {
  1212. lRet = RegSetValueEx(hKey,
  1213. Setting,
  1214. 0,
  1215. REG_DWORD,
  1216. (LPBYTE)&bVal,
  1217. dwSize);
  1218. RegCloseKey(hKey);
  1219. }
  1220. else
  1221. {
  1222. ErrorMessage(NULL, IDS_ERROR_TEXT3, (DWORD)lRet);
  1223. }
  1224. return (DWORD)lRet;
  1225. }
  1226. /****************************************************************************/
  1227. // SetSessionDirectoryEnabledState - sets SessionDirectoryActive regkey to bVal
  1228. /****************************************************************************/
  1229. DWORD CTSSessionDirectory::SetSessionDirectoryEnabledState(BOOL bVal)
  1230. {
  1231. return SetSessionDirectoryState(REG_TS_SESSDIRACTIVE, bVal);
  1232. }
  1233. /****************************************************************************/
  1234. // SetSessionDirectoryExposeIPState - sets SessionDirectoryExposeServerIP
  1235. // regkey to bVal
  1236. /****************************************************************************/
  1237. DWORD CTSSessionDirectory::SetSessionDirectoryExposeIPState(BOOL bVal)
  1238. {
  1239. return SetSessionDirectoryState(REG_TS_SESSDIR_EXPOSE_SERVER_ADDR, bVal);
  1240. }
  1241. /****************************************************************************/
  1242. // ErrorMessage --
  1243. /****************************************************************************/
  1244. void CTSSessionDirectory::ErrorMessage(HWND hwnd, UINT res, DWORD dwStatus)
  1245. {
  1246. TCHAR tchTitle[64];
  1247. TCHAR tchText[64];
  1248. TCHAR tchErrorMessage[256];
  1249. LPTSTR pBuffer = NULL;
  1250. // report error
  1251. ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1252. FORMAT_MESSAGE_FROM_SYSTEM,
  1253. NULL, //ignored
  1254. (DWORD)dwStatus, //message ID
  1255. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), //message language
  1256. (LPTSTR)&pBuffer, //address of buffer pointer
  1257. 0, //minimum buffer size
  1258. NULL);
  1259. LoadString(g_hInstance, IDS_ERROR_TITLE, tchTitle, sizeof(tchTitle) /
  1260. sizeof(TCHAR));
  1261. LoadString(g_hInstance, res, tchText, sizeof(tchText) / sizeof(TCHAR));
  1262. wsprintf(tchErrorMessage, tchText, pBuffer);
  1263. ::MessageBox(hwnd, tchErrorMessage, tchTitle, MB_OK | MB_ICONINFORMATION);
  1264. }
  1265. /****************************************************************************/
  1266. // CTSSessionDirectory::RecoveryThread
  1267. //
  1268. // Static helper function. The SDPtr passed in is a pointer to this for
  1269. // when _beginthreadex is called during init. RecoveryThread simply calls
  1270. // the real recovery function, which is RecoveryThreadEx.
  1271. /****************************************************************************/
  1272. unsigned __stdcall CTSSessionDirectory::RecoveryThread(void *SDPtr) {
  1273. ((CTSSessionDirectory *)SDPtr)->RecoveryThreadEx();
  1274. return 0;
  1275. }
  1276. /****************************************************************************/
  1277. // CTSSessionDirectory::RecoveryThreadEx
  1278. //
  1279. // Recovery thread for tssdjet recovery. Sits around and waits for the
  1280. // server to go down. When the server fails, it wakes up, sets a variable
  1281. // indicating that the server is unreachable, and then tries to reestablish
  1282. // a connection with the server. Meanwhile, further calls to the session
  1283. // directory simply fail without delay.
  1284. //
  1285. // When the session directory finally comes back up, the recovery thread
  1286. // temporarily halts session directory updates while repopulating the database.
  1287. // If all goes well, it cleans up and goes back to sleep. If all doesn't go
  1288. // well, it tries again.
  1289. //
  1290. // The recovery thread terminates if it fails a wait, or if m_hTerminateRecovery
  1291. // is set.
  1292. /****************************************************************************/
  1293. VOID CTSSessionDirectory::RecoveryThreadEx()
  1294. {
  1295. DWORD err = 0;
  1296. BOOL bErr;
  1297. CONST HANDLE lpHandles[] = {m_hTerminateRecovery, m_hSDServerDown, m_hIPChange};
  1298. WCHAR *pwszAddressList[SD_NUM_IP_ADDRESS];
  1299. DWORD dwNumAddr = SD_NUM_IP_ADDRESS, i;
  1300. BOOL bFoundIPMatch = FALSE;
  1301. DWORD Status;
  1302. HKEY hKey;
  1303. LONG lRet;
  1304. for ( ; ; ) {
  1305. // Wait forever until there is a problem with the session directory,
  1306. // or until we are told to shut down.
  1307. err = WaitForMultipleObjects(3, lpHandles, FALSE, INFINITE);
  1308. switch (err) {
  1309. case WAIT_OBJECT_0: // m_hTerminateRecovery
  1310. // We're quitting.
  1311. return;
  1312. case WAIT_OBJECT_0 + 1: // m_hSDServerDown
  1313. // SD Server Down--go through recovery.
  1314. break;
  1315. case WAIT_OBJECT_0 + 2: // m_hIPChange
  1316. // IP address changed --go through recovery.
  1317. TRC1((TB, "Get notified that IP changed"));
  1318. // wait for 15 seconds here so that RPC service can respond
  1319. // to IP change
  1320. Sleep(15 * 1000);
  1321. Status = NotifyAddrChange(&m_NotifyIPChange, &m_OverLapped);
  1322. if (ERROR_IO_PENDING == Status ) {
  1323. TRC1((TB, "Success: NotifyAddrChange returned IO_PENDING"));
  1324. }
  1325. else {
  1326. ERR((TB, "Failure: NotifyAddrChange returned %d", Status));
  1327. }
  1328. break;
  1329. default:
  1330. // This is unexpected. Assert on checked builds. On free,
  1331. // just return.
  1332. ASSERT(((err == WAIT_OBJECT_0) || (err == WAIT_OBJECT_0 + 1)),
  1333. (TB, "RecoveryThreadEx: Unexpected value from Wait!"));
  1334. return;
  1335. }
  1336. // we are disabling RPC connection to Session Directory
  1337. SetSDConnectionDown();
  1338. // Wait for all pending SD Rpcs to complete, and make all further
  1339. // EnterSDRpc's return FALSE until we're back up. Note that if there
  1340. // is a failure in recovery that this can be called more than once.
  1341. DisableSDRpcs();
  1342. // Destroy context handle if it's not NULL
  1343. if (m_hCI) {
  1344. RpcTryExcept {
  1345. RpcSsDestroyClientContext(&m_hCI);
  1346. } RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  1347. //
  1348. // The try/except is for that bad handles don't bring
  1349. // the process down
  1350. //
  1351. ERR((TB, "RpcSsDestroyClientContext raised an exception %d", RpcExceptionCode()));
  1352. } RpcEndExcept;
  1353. m_hCI = NULL;
  1354. }
  1355. // We need to tell if m_LocalServerAddress is a valid IP for SD redirection
  1356. // if not, we get a list of valid IPs and pick the 1st one as the SD redirection IP
  1357. // and write it to the SDRedirectionIP registry
  1358. // Initialize pwszAddressList first
  1359. for (i=0; i<dwNumAddr; i++) {
  1360. pwszAddressList[i] = NULL;
  1361. }
  1362. if (GetSDIPList(pwszAddressList, &dwNumAddr, TRUE) == S_OK) {
  1363. bFoundIPMatch = FALSE;
  1364. for (i=0; i<dwNumAddr; i++) {
  1365. if (!wcscmp(m_LocalServerAddress, pwszAddressList[i])) {
  1366. bFoundIPMatch = TRUE;
  1367. TRC1((TB, "The IP is in the list\n"));
  1368. break;
  1369. }
  1370. }
  1371. if (!bFoundIPMatch && (dwNumAddr != 0)) {
  1372. // Pick the 1st IP from the list
  1373. wcsncpy(m_LocalServerAddress, pwszAddressList[0], sizeof(m_LocalServerAddress) / sizeof(WCHAR));
  1374. }
  1375. }
  1376. else {
  1377. ERR((TB, "Get IP List Failed"));
  1378. }
  1379. // Write the IP to the registry
  1380. lRet= RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1381. REG_TS_CLUSTERSETTINGS,
  1382. 0,
  1383. KEY_READ | KEY_WRITE,
  1384. &hKey);
  1385. if (lRet == ERROR_SUCCESS) {
  1386. RegSetValueEx(hKey,
  1387. REG_TS_CLUSTER_REDIRECTIONIP,
  1388. 0,
  1389. REG_SZ,
  1390. (CONST LPBYTE) m_LocalServerAddress,
  1391. (DWORD)(wcslen(m_LocalServerAddress) *
  1392. sizeof(WCHAR)));
  1393. RegCloseKey(hKey);
  1394. }
  1395. // Free the memory allocated in GetSDIPList
  1396. for (i=0; i<dwNumAddr; i++) {
  1397. LocalFree(pwszAddressList[i]);
  1398. }
  1399. // This function loops and tries to reestablish a connection with the
  1400. // session directory. When it thinks it has one, it returns.
  1401. // If it returns nonzero, though, that means it was terminated or
  1402. // an error occurred in the wait, so terminate recovery.
  1403. if (ReestablishSessionDirectoryConnection() != 0)
  1404. return; // don't need to reset m_hInRepopulate.
  1405. // Set to non-signal - we are in repopulation.
  1406. ResetEvent( m_hInRepopulate );
  1407. // RPC connection is ready, let notify logon to go thru
  1408. SetSDConnectionReady();
  1409. // Now we have (theoretically) a session directory connection.
  1410. // Update the session directory. Nonzero on failure.
  1411. err = 0;
  1412. if (0 == (m_Flags & NO_REPOPULATE_SESSION)) {
  1413. err = RequestSessDirUpdate();
  1414. }
  1415. if (err != 0) {
  1416. // Failed in repopuation and we will loop back to establish
  1417. // connection again so set RPC connection to SD to down state.
  1418. SetSDConnectionDown();
  1419. // set to signal - we are not in repopulation any more.
  1420. SetEvent( m_hInRepopulate );
  1421. // Keep trying, so serverdown event stays signaled.
  1422. continue;
  1423. }
  1424. // Everything is good now. Clean up and wait for the next failure.
  1425. bErr = ResetEvent(m_hSDServerDown);
  1426. EnableSDRpcs();
  1427. // set to signal - we are not in repopulation any more.
  1428. SetEvent( m_hInRepopulate );
  1429. }
  1430. }
  1431. /****************************************************************************/
  1432. // StartupSD
  1433. //
  1434. // Initiates a connection by signaling to the recovery thread that the server
  1435. // is down.
  1436. /****************************************************************************/
  1437. void CTSSessionDirectory::StartupSD()
  1438. {
  1439. if (SetEvent(m_hSDServerDown) == FALSE) {
  1440. ERR((TB, "StartupSD: SetEvent failed. GetLastError=%d",
  1441. GetLastError()));
  1442. }
  1443. }
  1444. /****************************************************************************/
  1445. // NotifySDServerDown
  1446. //
  1447. // Tells the recovery thread that the server is down.
  1448. /****************************************************************************/
  1449. void CTSSessionDirectory::NotifySDServerDown()
  1450. {
  1451. if (SetEvent(m_hSDServerDown) == FALSE) {
  1452. ERR((TB, "NotifySDServerDown: SetEvent failed. GetLastError=%d",
  1453. GetLastError()));
  1454. }
  1455. }
  1456. /****************************************************************************/
  1457. // EnterSDRpc
  1458. //
  1459. // This function returns whether it is OK to make an RPC right now. It handles
  1460. // not letting anyone make an RPC call if RPCs are disabled, and also, if anyone
  1461. // is able to make an RPC, it ensures they will be able to do so until they call
  1462. // LeaveSDRpc.
  1463. //
  1464. // Return value:
  1465. // true - if OK to make RPC call, in which case you must call LeaveSDRpc when
  1466. // you are done.
  1467. // false - if not OK. You must not call LeaveSDRpc.
  1468. //
  1469. /****************************************************************************/
  1470. boolean CTSSessionDirectory::EnterSDRpc()
  1471. {
  1472. AcquireResourceShared(&m_sr);
  1473. if (m_SDIsUp) {
  1474. return TRUE;
  1475. }
  1476. else {
  1477. ReleaseResourceShared(&m_sr);
  1478. return FALSE;
  1479. }
  1480. }
  1481. /****************************************************************************/
  1482. // LeaveSDRpc
  1483. //
  1484. // If you were able to EnterSDRpc (i.e., it returned true), you must call this
  1485. // function when you are done with your Rpc call no matter what happened.
  1486. /****************************************************************************/
  1487. void CTSSessionDirectory::LeaveSDRpc()
  1488. {
  1489. ReleaseResourceShared(&m_sr);
  1490. }
  1491. /****************************************************************************/
  1492. // DisableSDRpcs
  1493. //
  1494. // Prevent new EnterSDRpcs from returning true, and then wait for all pending
  1495. // EnterSDRpcs to be matched by their LeaveSDRpc's.
  1496. /****************************************************************************/
  1497. void CTSSessionDirectory::DisableSDRpcs()
  1498. {
  1499. //
  1500. // First, set the flag that the SD is up to FALSE, preventing further Rpcs.
  1501. // Then, we grab the resource exclusive and release it right afterwards--
  1502. // this forces us to wait until all RPCs we're already in have completed.
  1503. //
  1504. (void) InterlockedExchange(&m_SDIsUp, FALSE);
  1505. AcquireResourceExclusive(&m_sr);
  1506. ReleaseResourceExclusive(&m_sr);
  1507. }
  1508. /****************************************************************************/
  1509. // EnableSDRpcs
  1510. //
  1511. // Enable EnterSDRpcs to return true once again.
  1512. /****************************************************************************/
  1513. void CTSSessionDirectory::EnableSDRpcs()
  1514. {
  1515. ASSERT((VerifyNoSharedAccess(&m_sr)),(TB,"EnableSDRpcs called but "
  1516. "shouldn't be when there are shared readers."));
  1517. (void) InterlockedExchange(&m_SDIsUp, TRUE);
  1518. }
  1519. /****************************************************************************/
  1520. // RequestSessDirUpdate
  1521. //
  1522. // Requests that termsrv update the session directory using the batchupdate
  1523. // interface.
  1524. //
  1525. // This function needs to know whether the update succeeded and return 0 on
  1526. // success, nonzero on failure.
  1527. /****************************************************************************/
  1528. DWORD CTSSessionDirectory::RequestSessDirUpdate()
  1529. {
  1530. return (*m_repopfn)();
  1531. }
  1532. /****************************************************************************/
  1533. // ReestablishSessionDirectoryConnection
  1534. //
  1535. // This function loops and tries to reestablish a connection with the
  1536. // session directory. When it has one, it returns.
  1537. //
  1538. // Return value: 0 if normal exit, nonzero if terminated by TerminateRecovery
  1539. // event.
  1540. /****************************************************************************/
  1541. DWORD CTSSessionDirectory::ReestablishSessionDirectoryConnection()
  1542. {
  1543. HRESULT hr;
  1544. unsigned long RpcException;
  1545. DWORD err;
  1546. WCHAR *szPrincipalName = NULL;
  1547. RPC_SECURITY_QOS RPCSecurityQos;
  1548. SEC_WINNT_AUTH_IDENTITY_EX CurrentIdentity;
  1549. WCHAR CurrentUserName[SDNAMELENGTH];
  1550. DWORD cchBuff;
  1551. WCHAR SDComputerName[SDNAMELENGTH];
  1552. unsigned int FailCountBeforeClearFlag = 0;
  1553. WCHAR LocalIPAddress[64];
  1554. WCHAR *pBindingString = NULL;
  1555. RPCSecurityQos.Version = RPC_C_SECURITY_QOS_VERSION;
  1556. RPCSecurityQos.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  1557. RPCSecurityQos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
  1558. RPCSecurityQos.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
  1559. CurrentIdentity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
  1560. CurrentIdentity.Length = sizeof(SEC_WINNT_AUTH_IDENTITY_EX);
  1561. CurrentIdentity.Password = NULL;
  1562. CurrentIdentity.PasswordLength = 0;
  1563. CurrentIdentity.Domain = NULL;
  1564. CurrentIdentity.DomainLength = 0;
  1565. CurrentIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  1566. CurrentIdentity.PackageList = SECPACKAGELIST;
  1567. CurrentIdentity.PackageListLength = (unsigned long)wcslen(SECPACKAGELIST);
  1568. cchBuff = sizeof(CurrentUserName) / sizeof(WCHAR);
  1569. GetComputerNameEx(ComputerNamePhysicalNetBIOS, CurrentUserName, &cchBuff);
  1570. wcscat(CurrentUserName, L"$");
  1571. CurrentIdentity.User = CurrentUserName;
  1572. CurrentIdentity.UserLength = (unsigned long)wcslen(CurrentUserName);
  1573. if (m_hRPCBinding) {
  1574. RpcBindingFree(&m_hRPCBinding);
  1575. m_hRPCBinding = NULL;
  1576. }
  1577. // Connect to the Jet RPC server according to the server name provided.
  1578. // We first create an RPC binding handle from a composed binding string.
  1579. hr = RpcStringBindingCompose(/*(WCHAR *)g_RPCUUID,*/
  1580. 0,
  1581. (WCHAR *)g_RPCProtocolSequence, m_StoreServerName,
  1582. /*(WCHAR *)g_RPCRemoteEndpoint, */
  1583. 0,
  1584. NULL, &pBindingString);
  1585. if (hr == RPC_S_OK) {
  1586. // Generate the RPC binding from the canonical RPC binding string.
  1587. hr = RpcBindingFromStringBinding(pBindingString, &m_hRPCBinding);
  1588. if (hr != RPC_S_OK) {
  1589. ERR((TB,"Init: Error %d in RpcBindingFromStringBinding\n", hr));
  1590. PostSDJetErrorValueEvent(EVENT_FAIL_RPCBINDINGFROMSTRINGBINDING, hr, EVENTLOG_ERROR_TYPE);
  1591. m_hRPCBinding = NULL;
  1592. goto ExitFunc;
  1593. }
  1594. }
  1595. else {
  1596. ERR((TB,"Init: Error %d in RpcStringBindingCompose\n", hr));
  1597. PostSDJetErrorValueEvent(EVENT_FAIL_RPCSTRINGBINDINGCOMPOSE, hr, EVENTLOG_ERROR_TYPE);
  1598. pBindingString = NULL;
  1599. goto ExitFunc;
  1600. }
  1601. m_RecoveryTimeout = JET_RECOVERY_TIMEOUT;
  1602. for ( ; ; ) {
  1603. // If the machine joins the SD during the OS boot time, we may get the local IP
  1604. // as the localhost (127.0.0.1) since DHCP is not started yet. Therefore we need
  1605. // to reget the local IP here
  1606. if (!wcscmp(m_LocalServerAddress, L"127.0.0.1")) {
  1607. if (0 != TSSDJetGetLocalIPAddr(LocalIPAddress)) {
  1608. goto HandleError;
  1609. }
  1610. if (wcscmp(LocalIPAddress, L"127.0.0.1")) {
  1611. wcscpy(m_LocalServerAddress, LocalIPAddress);
  1612. }
  1613. else {
  1614. goto HandleError;
  1615. }
  1616. }
  1617. hr = RpcBindingReset(m_hRPCBinding);
  1618. if (hr != RPC_S_OK) {
  1619. ERR((TB, "Recover: Error %d in RpcBindingReset", hr));
  1620. PostSDJetErrorValueEvent(EVENT_FAIL_RPCBINDINGRESET, hr, EVENTLOG_ERROR_TYPE);
  1621. goto HandleError;
  1622. }
  1623. hr = RpcEpResolveBinding(m_hRPCBinding, TSSDJetRPC_ClientIfHandle);
  1624. if (hr != RPC_S_OK) {
  1625. ERR((TB, "Recover: Error %d in RpcEpResolveBinding", hr));
  1626. if (RPC_S_SERVER_UNAVAILABLE == hr) {
  1627. PostSDJetErrorMsgEvent(EVENT_SESSIONDIRECTORY_NAME_INVALID, m_StoreServerName, EVENTLOG_ERROR_TYPE);
  1628. }
  1629. else {
  1630. PostSDJetErrorMsgEvent(EVENT_SESSIONDIRECTORY_UNAVAILABLE, m_StoreServerName, EVENTLOG_ERROR_TYPE);
  1631. }
  1632. goto HandleError;
  1633. }
  1634. hr = RpcMgmtInqServerPrincName(m_hRPCBinding,
  1635. RPC_C_AUTHN_GSS_NEGOTIATE,
  1636. &szPrincipalName);
  1637. if (hr != RPC_S_OK) {
  1638. ERR((TB,"Recover: Error %d in RpcMgmtIngServerPrincName", hr));
  1639. PostSDJetErrorValueEvent(EVENT_FAIL_RPCMGMTINGSERVERPRINCNAME, hr, EVENTLOG_ERROR_TYPE);
  1640. goto HandleError;
  1641. }
  1642. //hr = RpcBindingSetAuthInfo(m_hRPCBinding, szPrincipalName,
  1643. // RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE, 0, 0);
  1644. hr = RpcBindingSetAuthInfoEx(m_hRPCBinding,
  1645. szPrincipalName,
  1646. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  1647. RPC_C_AUTHN_GSS_NEGOTIATE,
  1648. &CurrentIdentity,
  1649. NULL,
  1650. &RPCSecurityQos);
  1651. if (hr != RPC_S_OK) {
  1652. ERR((TB,"Recover: Error %d in RpcBindingSetAuthInfo", hr));
  1653. PostSDJetErrorValueEvent(EVENT_FAIL_RPCBINDINGSETAUTHINFOEX, hr, EVENTLOG_ERROR_TYPE);
  1654. goto HandleError;
  1655. }
  1656. // This option enable SD to get fresh machine logon info for tssdjet RPC call
  1657. hr = RpcBindingSetOption(m_hRPCBinding, RPC_C_OPT_DONT_LINGER, 1);
  1658. if (hr != RPC_S_OK) {
  1659. ERR((TB,"Recover: Error %d in RpcBindingSetOption", hr));
  1660. PostSDJetErrorValueEvent(EVENT_FAIL_RPCBIDINGSETOPTION, hr, EVENTLOG_ERROR_TYPE);
  1661. // Per Chenyz's comment, this is OK.
  1662. // goto HandleError;
  1663. }
  1664. // Session Directory need to know the DNS host name of the TS server
  1665. cchBuff = SDNAMELENGTH;
  1666. GetComputerNameEx(ComputerNamePhysicalDnsFullyQualified, SDComputerName, &cchBuff);
  1667. // Execute ServerOnline.
  1668. RpcTryExcept {
  1669. hr = TSSDRpcServerOnline(m_hRPCBinding, m_ClusterName, &m_hCI,
  1670. m_Flags, SDComputerName, m_LocalServerAddress);
  1671. }
  1672. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  1673. m_hCI = NULL;
  1674. RpcException = RpcExceptionCode();
  1675. ERR((TB, "rpcserveronline returns exception: %u", RpcException));
  1676. hr = RpcException;
  1677. }
  1678. RpcEndExcept
  1679. // RPC got access denied by SD
  1680. if (hr == ERROR_ACCESS_DENIED) {
  1681. ERR((TB, "rpcserveronline returns access denied error: %u", hr));
  1682. PostSDJetErrorMsgEvent(EVENT_RPC_ACCESS_DENIED, m_StoreServerName, EVENTLOG_ERROR_TYPE);
  1683. goto HandleError;
  1684. }
  1685. if (SUCCEEDED(hr)) {
  1686. RpcTryExcept {
  1687. hr = TSSDRpcUpdateConfigurationSetting(m_hRPCBinding, &m_hCI,
  1688. SDCONFIG_SERVER_ADDRESS,
  1689. (DWORD) (wcslen(m_LocalServerAddress) + 1) *
  1690. sizeof(WCHAR), (PBYTE) m_LocalServerAddress);
  1691. }
  1692. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  1693. m_hCI = NULL;
  1694. RpcException = RpcExceptionCode();
  1695. hr = E_FAIL;
  1696. }
  1697. RpcEndExcept
  1698. if (SUCCEEDED(hr)) {
  1699. PostSDJetErrorMsgEvent(EVENT_JOIN_SESSIONDIRECTORY_SUCESS, m_StoreServerName, EVENTLOG_SUCCESS);
  1700. LookUpSDComputerSID(SDComputerName);
  1701. return 0;
  1702. }
  1703. }
  1704. else {
  1705. ERR((TB, "TSSDRpcServerOnline: 0x%08x", hr));
  1706. PostSDJetErrorValueEvent(EVENT_JOIN_SESSIONDIRECTORY_FAIL, hr, EVENTLOG_ERROR_TYPE);
  1707. ASSERT( SUCCEEDED(hr),(TB, "TSSDRpcServerOnline: failed with 0x%08x", hr));
  1708. }
  1709. HandleError:
  1710. // If joining SD fails, we need to clear NO_REPOPULATE_SESSION so that
  1711. // the next join will repopulate sessions
  1712. FailCountBeforeClearFlag++;
  1713. if (FailCountBeforeClearFlag > TSSD_FAILCOUNT_BEFORE_CLEARFLAG) {
  1714. m_Flags &= (~NO_REPOPULATE_SESSION);
  1715. }
  1716. if (szPrincipalName != NULL) {
  1717. RpcStringFree(&szPrincipalName);
  1718. szPrincipalName = NULL;
  1719. }
  1720. if (pBindingString != NULL) {
  1721. RpcStringFree(&pBindingString);
  1722. pBindingString = NULL;
  1723. }
  1724. err = WaitForSingleObject(m_hTerminateRecovery, m_RecoveryTimeout);
  1725. if (err != WAIT_TIMEOUT) {
  1726. // It was not a timeout, it better be our terminate recovery event.
  1727. ASSERT((err == WAIT_OBJECT_0),(TB, "ReestSessDirConn: Unexpected "
  1728. "value returned from wait"));
  1729. // If it was not our event, we want to keep going through
  1730. // this loop so this thread does not terminate.
  1731. if (err == WAIT_OBJECT_0)
  1732. return 1;
  1733. }
  1734. }
  1735. ExitFunc:
  1736. if (pBindingString != NULL) {
  1737. RpcStringFree(&pBindingString);
  1738. pBindingString = NULL;
  1739. }
  1740. return 1;
  1741. }
  1742. /****************************************************************************/
  1743. // CTSSessionDirectory::PingSD
  1744. //
  1745. // This function is called to see if Session Directory is accessible or not
  1746. //
  1747. // Arguments: pszServerName -- Session Directory server name
  1748. //
  1749. // Return value: DWORD ERROR_SUCCESS if SD is accessible, otherwise return error code
  1750. /****************************************************************************/
  1751. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::PingSD(PWCHAR pszServerName)
  1752. {
  1753. DWORD hr = ERROR_SUCCESS;
  1754. RPC_BINDING_HANDLE hRPCBinding = NULL;
  1755. WCHAR *szPrincipalName = NULL;
  1756. RPC_SECURITY_QOS RPCSecurityQos;
  1757. SEC_WINNT_AUTH_IDENTITY_EX CurrentIdentity;
  1758. WCHAR CurrentUserName[SDNAMELENGTH+1];
  1759. DWORD cchBuff = 0;
  1760. WCHAR *pBindingString = NULL;
  1761. RPCSecurityQos.Version = RPC_C_SECURITY_QOS_VERSION;
  1762. RPCSecurityQos.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  1763. RPCSecurityQos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
  1764. RPCSecurityQos.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
  1765. CurrentIdentity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
  1766. CurrentIdentity.Length = sizeof(SEC_WINNT_AUTH_IDENTITY_EX);
  1767. CurrentIdentity.Password = NULL;
  1768. CurrentIdentity.PasswordLength = 0;
  1769. CurrentIdentity.Domain = NULL;
  1770. CurrentIdentity.DomainLength = 0;
  1771. CurrentIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  1772. CurrentIdentity.PackageList = SECPACKAGELIST;
  1773. CurrentIdentity.PackageListLength = (unsigned long)wcslen(SECPACKAGELIST);
  1774. // we need one for NULL and one for wcscat() below.
  1775. cchBuff = sizeof(CurrentUserName) / sizeof(CurrentUserName[0]) - 2;
  1776. if (!GetComputerNameEx(ComputerNamePhysicalNetBIOS, CurrentUserName, &cchBuff)) {
  1777. ERR((TB,"Error %d in GetComputerNameEx\n", GetLastError()));
  1778. goto ExitFunc;
  1779. }
  1780. wcscat(CurrentUserName, L"$");
  1781. CurrentIdentity.User = CurrentUserName;
  1782. CurrentIdentity.UserLength = (unsigned long)wcslen(CurrentUserName);
  1783. // Connect to the Jet RPC server according to the server name provided.
  1784. // We first create an RPC binding handle from a composed binding string.
  1785. hr = RpcStringBindingCompose(/*(WCHAR *)g_RPCUUID,*/
  1786. 0,
  1787. (WCHAR *)g_RPCProtocolSequence,
  1788. pszServerName,
  1789. 0,
  1790. NULL,
  1791. &pBindingString);
  1792. if (hr != RPC_S_OK) {
  1793. ERR((TB,"Error %d in RpcStringBindingCompose\n", hr));
  1794. pBindingString = NULL;
  1795. goto ExitFunc;
  1796. }
  1797. // Generate the RPC binding from the canonical RPC binding string.
  1798. hr = RpcBindingFromStringBinding(pBindingString, &hRPCBinding);
  1799. if (hr != RPC_S_OK) {
  1800. ERR((TB,"Error %d in RpcBindingFromStringBinding\n", hr));
  1801. hRPCBinding = NULL;
  1802. goto ExitFunc;
  1803. }
  1804. hr = RpcEpResolveBinding(hRPCBinding, TSSDJetRPC_ClientIfHandle);
  1805. if (hr != RPC_S_OK) {
  1806. ERR((TB, "Error %d in RpcEpResolveBinding", hr));
  1807. goto ExitFunc;
  1808. }
  1809. hr = RpcMgmtInqServerPrincName(hRPCBinding,
  1810. RPC_C_AUTHN_GSS_NEGOTIATE,
  1811. &szPrincipalName);
  1812. if (hr != RPC_S_OK) {
  1813. ERR((TB,"Error %d in RpcMgmtIngServerPrincName", hr));
  1814. goto ExitFunc;
  1815. }
  1816. hr = RpcBindingSetAuthInfoEx(hRPCBinding,
  1817. szPrincipalName,
  1818. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  1819. RPC_C_AUTHN_GSS_NEGOTIATE,
  1820. &CurrentIdentity,
  1821. NULL,
  1822. &RPCSecurityQos);
  1823. if (hr != RPC_S_OK) {
  1824. ERR((TB,"Error %d in RpcBindingSetAuthInfo", hr));
  1825. goto ExitFunc;
  1826. }
  1827. // This option enable SD to get fresh machine logon info for tssdjet RPC call
  1828. hr = RpcBindingSetOption(hRPCBinding, RPC_C_OPT_DONT_LINGER, 1);
  1829. if (hr != RPC_S_OK) {
  1830. ERR((TB,"Error %d in RpcBindingSetOption", hr));
  1831. // This error can be ignore
  1832. //goto ExitFunc;
  1833. }
  1834. // Execute IsSDAccessible.
  1835. RpcTryExcept {
  1836. hr = TSSDRpcPingSD(hRPCBinding);
  1837. }
  1838. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  1839. hr = RpcExceptionCode();
  1840. ERR((TB, "TSSDPingSD returns exception: %u", hr));
  1841. }
  1842. RpcEndExcept
  1843. ExitFunc:
  1844. if (szPrincipalName != NULL) {
  1845. RpcStringFree(&szPrincipalName);
  1846. szPrincipalName = NULL;
  1847. }
  1848. if (pBindingString != NULL) {
  1849. RpcStringFree(&pBindingString);
  1850. pBindingString = NULL;
  1851. }
  1852. if( hRPCBinding != NULL ) {
  1853. RpcBindingFree( &hRPCBinding );
  1854. hRPCBinding = NULL;
  1855. }
  1856. return HRESULT_FROM_WIN32(hr);
  1857. }
  1858. /****************************************************************************/
  1859. // CTSSessionDirectory::Terminate
  1860. //
  1861. // Helper function called by the destructor and by Update when switching to
  1862. // another server. Frees RPC binding, events, and recovery thread.
  1863. /****************************************************************************/
  1864. void CTSSessionDirectory::Terminate()
  1865. {
  1866. HRESULT rc = S_OK;
  1867. unsigned long RpcException;
  1868. BOOL ConnectionMaybeUp;
  1869. // we are terminating RPC connection to Session Directory
  1870. SetSDConnectionDown();
  1871. // Terminate recovery.
  1872. if (m_hRecoveryThread != NULL) {
  1873. SetEvent(m_hTerminateRecovery);
  1874. WaitForSingleObject((HANDLE) m_hRecoveryThread, INFINITE);
  1875. m_hRecoveryThread = NULL;
  1876. }
  1877. ConnectionMaybeUp = EnterSDRpc();
  1878. if (ConnectionMaybeUp)
  1879. LeaveSDRpc();
  1880. // Wait for current Rpcs to complete (if any), disable new ones.
  1881. DisableSDRpcs();
  1882. // If we think there is a connection, disconnect it.
  1883. if (ConnectionMaybeUp) {
  1884. RpcTryExcept {
  1885. rc = TSSDRpcServerOffline(m_hRPCBinding, &m_hCI);
  1886. m_hCI = NULL;
  1887. if (FAILED(rc)) {
  1888. ERR((TB,"Term: SvrOffline failed, lasterr=0x%X", GetLastError()));
  1889. PostSDJetErrorValueEvent(EVENT_CALL_TSSDRPCSEVEROFFLINE_FAIL, GetLastError(), EVENTLOG_WARNING_TYPE);
  1890. }
  1891. }
  1892. RpcExcept(TSSDRpcExceptionFilter(RpcExceptionCode())) {
  1893. RpcException = RpcExceptionCode();
  1894. ERR((TB,"Term: RPC Exception %d\n", RpcException));
  1895. PostSDJetErrorValueEvent(EVENT_CALL_TSSDRPCSEVEROFFLINE_FAIL, RpcException, EVENTLOG_WARNING_TYPE);
  1896. rc = E_FAIL;
  1897. }
  1898. RpcEndExcept
  1899. }
  1900. // Clean up.
  1901. if (m_hRPCBinding != NULL) {
  1902. RpcBindingFree(&m_hRPCBinding);
  1903. m_hRPCBinding = NULL;
  1904. }
  1905. if (m_hSDServerDown != NULL) {
  1906. CloseHandle(m_hSDServerDown);
  1907. m_hSDServerDown = NULL;
  1908. }
  1909. if (m_hTerminateRecovery != NULL) {
  1910. CloseHandle(m_hTerminateRecovery);
  1911. m_hTerminateRecovery = NULL;
  1912. }
  1913. if (m_hIPChange != NULL) {
  1914. CloseHandle(m_hIPChange);
  1915. m_hIPChange = NULL;
  1916. }
  1917. #if 0
  1918. // wrong assert, timing issue, reader might just happen to increment counter
  1919. // TODO - fix this so we can trap problem.
  1920. if (m_sr.Valid == TRUE) {
  1921. // We clean up only in the destructor, because we may initialize again.
  1922. // On check builds verify that no one is currently accessing.
  1923. ASSERT((VerifyNoSharedAccess(&m_sr)), (TB, "Terminate: Shared readers"
  1924. " exist!"));
  1925. }
  1926. #endif
  1927. }
  1928. /****************************************************************************/
  1929. // CTSSessionDirectory::GetLoadBalanceInfo
  1930. //
  1931. // Based on the server address, generate load balance info to send to the client
  1932. /****************************************************************************/
  1933. HRESULT STDMETHODCALLTYPE CTSSessionDirectory::GetLoadBalanceInfo(
  1934. LPWSTR ServerAddress,
  1935. BSTR* LBInfo)
  1936. {
  1937. HRESULT hr = S_OK;
  1938. // This is for test only
  1939. //WCHAR lbInfo[MAX_PATH];
  1940. //wcscpy(lbInfo, L"load balance info");
  1941. *LBInfo = NULL;
  1942. TRC2((TB,"GetLoadBalanceInfo"));
  1943. if (ServerAddress) {
  1944. //
  1945. // "Cookie: msts=4294967295.65535.0000" + CR + LF + NULL, on 8-byte
  1946. // boundary is 40 bytes.
  1947. //
  1948. // The format of the cookie for F5 is, for an IP of 1.2.3.4
  1949. // using port 3389, Cookie: msts=67305985.15629.0000 + CR + LF + NULL.
  1950. //
  1951. #define TEMPLATE_STRING_LENGTH 40
  1952. #define SERVER_ADDRESS_LENGTH 64
  1953. char CookieTemplate[TEMPLATE_STRING_LENGTH];
  1954. char AnsiServerAddress[SERVER_ADDRESS_LENGTH];
  1955. unsigned long NumericalServerAddr = 0;
  1956. int retval;
  1957. // Compute integer for the server address.
  1958. // First, get ServerAddress as an ANSI string.
  1959. retval = WideCharToMultiByte(CP_ACP, 0, ServerAddress, -1,
  1960. AnsiServerAddress, SERVER_ADDRESS_LENGTH, NULL, NULL);
  1961. if (retval == 0) {
  1962. TRC2((TB, "GetLoadBalanceInfo WideCharToMB failed %d",
  1963. GetLastError()));
  1964. return E_INVALIDARG;
  1965. }
  1966. // Now, use inet_addr to turn into an unsigned long.
  1967. NumericalServerAddr = inet_addr(AnsiServerAddress);
  1968. if (NumericalServerAddr == INADDR_NONE) {
  1969. TRC2((TB, "GetLoadBalanceInfo inet_addr failed"));
  1970. return E_INVALIDARG;
  1971. }
  1972. // Compute the total cookie string. 0x3d0d is 3389 in correct byte
  1973. // order. We need to change this to whatever the port number has been
  1974. // configured to.
  1975. sprintf(CookieTemplate, "Cookie: msts=%u.%u.0000\r\n",
  1976. NumericalServerAddr, 0x3d0d);
  1977. // Generate returned BSTR.
  1978. *LBInfo = SysAllocStringByteLen((LPCSTR)CookieTemplate,
  1979. (UINT) strlen(CookieTemplate));
  1980. if (*LBInfo) {
  1981. TRC2((TB,"GetLoadBalanceInfo: okay"));
  1982. hr = S_OK;
  1983. }
  1984. else {
  1985. TRC2((TB,"GetLoadBalanceInfo: failed"));
  1986. hr = E_OUTOFMEMORY;
  1987. }
  1988. }
  1989. else {
  1990. TRC2((TB,"GetLoadBalanceInfo: failed"));
  1991. hr = E_FAIL;
  1992. }
  1993. return hr;
  1994. }
  1995. /****************************************************************************/
  1996. // IsServerNameValid
  1997. //
  1998. // This function tries to ping the server name to determine if its a valid
  1999. // entry
  2000. //
  2001. // Return value: FALSE if we cannot ping.
  2002. // event.
  2003. /****************************************************************************/
  2004. BOOL IsServerNameValid(
  2005. wchar_t * pwszName ,
  2006. PDWORD pdwStatus
  2007. )
  2008. {
  2009. HCURSOR hCursor = NULL;
  2010. long inaddr;
  2011. char szAnsiServerName[256];
  2012. struct hostent *hostp = NULL;
  2013. BOOL bRet = TRUE;
  2014. if (pwszName == NULL || pwszName[0] == '\0' || pdwStatus == NULL )
  2015. {
  2016. bRet = FALSE;
  2017. }
  2018. else
  2019. {
  2020. *pdwStatus = ERROR_SUCCESS;
  2021. hCursor = SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)));
  2022. // some winsock apis does accept wides.
  2023. WideCharToMultiByte(CP_ACP,
  2024. 0,
  2025. pwszName,
  2026. -1,
  2027. szAnsiServerName,
  2028. sizeof(szAnsiServerName),
  2029. NULL,
  2030. NULL);
  2031. //
  2032. // check ip format return true do a dns lookup.
  2033. //
  2034. if( ( inaddr = inet_addr( szAnsiServerName ) ) == INADDR_NONE )
  2035. {
  2036. hostp = gethostbyname( szAnsiServerName );
  2037. if( hostp == NULL )
  2038. {
  2039. // Neither dotted, not name.
  2040. bRet = FALSE;
  2041. }
  2042. }
  2043. if( bRet )
  2044. {
  2045. bRet = _WinStationOpenSessionDirectory( SERVERNAME_CURRENT , pwszName );
  2046. *pdwStatus = GetLastError();
  2047. }
  2048. SetCursor( hCursor );
  2049. }
  2050. return bRet;
  2051. }
  2052. BOOL OnHelp(HWND hwnd, LPHELPINFO lphi)
  2053. {
  2054. UNREFERENCED_PARAMETER(hwnd);
  2055. TCHAR tchHelpFile[MAX_PATH];
  2056. //
  2057. // For the information to winhelp api
  2058. //
  2059. if (IsBadReadPtr(lphi, sizeof(HELPINFO)))
  2060. {
  2061. return FALSE;
  2062. }
  2063. if (lphi->iCtrlId <= -1)
  2064. {
  2065. return FALSE;
  2066. }
  2067. LoadString(g_hInstance, IDS_HELPFILE, tchHelpFile,
  2068. sizeof (tchHelpFile) / sizeof(TCHAR));
  2069. ULONG_PTR rgdw[2];
  2070. rgdw[0] = (ULONG_PTR)lphi->iCtrlId;
  2071. rgdw[1] = (ULONG_PTR)lphi->dwContextId;
  2072. WinHelp((HWND) lphi->hItemHandle, tchHelpFile, HELP_WM_HELP,
  2073. (ULONG_PTR) &rgdw);
  2074. return TRUE;
  2075. }
  2076. /****************************************************************************/
  2077. // Custom UI msg handler dealt with here
  2078. /****************************************************************************/
  2079. INT_PTR CALLBACK CustomUIDlg(HWND hwnd, UINT umsg, WPARAM wp, LPARAM lp)
  2080. {
  2081. static BOOL s_fServerNameChanged;
  2082. static BOOL s_fClusterNameChanged;
  2083. static BOOL s_fRedirectIPChanged;
  2084. static BOOL s_fPreviousButtonState;
  2085. static BOOL s_fPreviousExposeIPState;
  2086. CTSSessionDirectory *pCTssd;
  2087. POLICY_TS_MACHINE gpolicy;
  2088. switch(umsg)
  2089. {
  2090. case WM_INITDIALOG:
  2091. {
  2092. BOOL bEnable = FALSE;
  2093. BOOL bExposeIP = FALSE;
  2094. pCTssd = (CTSSessionDirectory *)lp;
  2095. SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pCTssd);
  2096. SendMessage(GetDlgItem(hwnd, IDC_EDIT_SERVERNAME),
  2097. EM_LIMITTEXT,
  2098. (WPARAM)64,
  2099. 0);
  2100. SendMessage(GetDlgItem(hwnd, IDC_EDIT_CLUSTERNAME),
  2101. EM_LIMITTEXT,
  2102. (WPARAM)64,
  2103. 0);
  2104. SendMessage(GetDlgItem(hwnd, IDC_EDIT_ACCOUNTNAME),
  2105. EM_LIMITTEXT,
  2106. (WPARAM)64,
  2107. 0);
  2108. SendMessage(GetDlgItem(hwnd, IDC_EDIT_PASSWORD),
  2109. EM_LIMITTEXT,
  2110. (WPARAM)64,
  2111. 0);
  2112. HICON hIcon;
  2113. hIcon = (HICON)LoadImage(
  2114. g_hInstance,
  2115. MAKEINTRESOURCE(IDI_SMALLWARN),
  2116. IMAGE_ICON,
  2117. 0,
  2118. 0,
  2119. 0);
  2120. // TRC1((TB, "CustomUIDlg - LoadImage returned 0x%p",hIcon));
  2121. SendMessage(
  2122. GetDlgItem(hwnd, IDC_WARNING_ICON),
  2123. STM_SETICON,
  2124. (WPARAM)hIcon,
  2125. (LPARAM)0
  2126. );
  2127. LONG lRet;
  2128. HKEY hKey;
  2129. DWORD cbData = 256;
  2130. TCHAR szString[256];
  2131. RegGetMachinePolicy(&gpolicy);
  2132. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2133. REG_TS_CLUSTERSETTINGS,
  2134. 0,
  2135. KEY_READ | KEY_WRITE,
  2136. &hKey);
  2137. if (lRet == ERROR_SUCCESS)
  2138. {
  2139. lRet = RegQueryValueEx(hKey,
  2140. REG_TS_CLUSTER_STORESERVERNAME,
  2141. NULL,
  2142. NULL,
  2143. (LPBYTE)szString,
  2144. &cbData);
  2145. if (lRet == ERROR_SUCCESS)
  2146. {
  2147. SetWindowText(GetDlgItem(hwnd, IDC_EDIT_SERVERNAME),
  2148. szString);
  2149. }
  2150. cbData = 256;
  2151. lRet = RegQueryValueEx(hKey,
  2152. REG_TS_CLUSTER_CLUSTERNAME,
  2153. NULL,
  2154. NULL,
  2155. (LPBYTE)szString,
  2156. &cbData);
  2157. if (lRet == ERROR_SUCCESS)
  2158. {
  2159. SetWindowText(GetDlgItem(hwnd, IDC_EDIT_CLUSTERNAME),
  2160. szString);
  2161. }
  2162. RegCloseKey(hKey);
  2163. }
  2164. else
  2165. {
  2166. if (pCTssd != NULL)
  2167. {
  2168. pCTssd->ErrorMessage(hwnd, IDS_ERROR_TEXT, (DWORD)lRet);
  2169. }
  2170. EndDialog(hwnd, lRet);
  2171. }
  2172. if (gpolicy.fPolicySessionDirectoryActive)
  2173. {
  2174. bEnable = gpolicy.SessionDirectoryActive;
  2175. EnableWindow(GetDlgItem(hwnd, IDC_CHECK_ENABLE), FALSE);
  2176. }
  2177. else
  2178. {
  2179. if (pCTssd != NULL)
  2180. bEnable = pCTssd->IsSessionDirectoryEnabled();
  2181. }
  2182. s_fPreviousButtonState = bEnable;
  2183. CheckDlgButton(hwnd, IDC_CHECK_ENABLE, bEnable);
  2184. if (gpolicy.fPolicySessionDirectoryLocation)
  2185. {
  2186. SetWindowText(GetDlgItem(hwnd, IDC_EDIT_SERVERNAME),
  2187. gpolicy.SessionDirectoryLocation);
  2188. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_SERVERNAME), FALSE);
  2189. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_STORENAME), FALSE);
  2190. }
  2191. else
  2192. {
  2193. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_SERVERNAME), bEnable);
  2194. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_STORENAME), bEnable);
  2195. }
  2196. if (gpolicy.fPolicySessionDirectoryClusterName != 0)
  2197. {
  2198. SetWindowText(GetDlgItem(hwnd, IDC_EDIT_CLUSTERNAME),
  2199. gpolicy.SessionDirectoryClusterName);
  2200. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_CLUSTERNAME), FALSE);
  2201. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_CLUSTERNAME),FALSE);
  2202. }
  2203. else
  2204. {
  2205. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_CLUSTERNAME), bEnable);
  2206. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_CLUSTERNAME),bEnable);
  2207. }
  2208. if (gpolicy.fPolicySessionDirectoryExposeServerIP != 0)
  2209. {
  2210. bExposeIP = gpolicy.SessionDirectoryExposeServerIP;
  2211. CheckDlgButton(hwnd, IDC_CHECK_EXPOSEIP, bExposeIP);
  2212. EnableWindow(GetDlgItem(hwnd, IDC_CHECK_EXPOSEIP), FALSE);
  2213. }
  2214. else
  2215. {
  2216. if (pCTssd != NULL)
  2217. {
  2218. bExposeIP =
  2219. pCTssd->IsSessionDirectoryExposeServerIPEnabled();
  2220. }
  2221. CheckDlgButton(hwnd, IDC_CHECK_EXPOSEIP, bExposeIP ?
  2222. BST_CHECKED : BST_UNCHECKED);
  2223. EnableWindow(GetDlgItem(hwnd, IDC_CHECK_EXPOSEIP), bEnable);
  2224. }
  2225. EnableWindow(GetDlgItem(hwnd, IDC_IPCOMBO), bEnable);
  2226. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_IPCOMBO), bEnable);
  2227. // Get handle to Combo Box
  2228. HWND hIPComboBox;
  2229. hIPComboBox = GetDlgItem(hwnd, IDC_IPCOMBO);
  2230. // Get list of Adapters and IP address and populate the combo box
  2231. // If it fails to populate, just fall through and continue
  2232. QueryNetworkAdapterAndIPs(hIPComboBox);
  2233. s_fPreviousExposeIPState = bExposeIP;
  2234. s_fServerNameChanged = FALSE;
  2235. s_fClusterNameChanged = FALSE;
  2236. s_fRedirectIPChanged = FALSE;
  2237. }
  2238. break;
  2239. case WM_HELP:
  2240. OnHelp(hwnd, (LPHELPINFO)lp);
  2241. break;
  2242. case WM_COMMAND:
  2243. if (LOWORD(wp) == IDCANCEL)
  2244. {
  2245. EndDialog(hwnd, 0);
  2246. }
  2247. else if (LOWORD(wp) == IDOK)
  2248. {
  2249. BOOL bEnabled;
  2250. BOOL bExposeIP;
  2251. DWORD dwRetStatus = 0;
  2252. pCTssd = (CTSSessionDirectory *) GetWindowLongPtr(hwnd,
  2253. DWLP_USER);
  2254. bEnabled = (IsDlgButtonChecked(hwnd, IDC_CHECK_ENABLE) ==
  2255. BST_CHECKED);
  2256. bExposeIP = (IsDlgButtonChecked(hwnd, IDC_CHECK_EXPOSEIP) ==
  2257. BST_CHECKED);
  2258. if (bEnabled != s_fPreviousButtonState)
  2259. {
  2260. DWORD dwStatus;
  2261. dwStatus = pCTssd->SetSessionDirectoryEnabledState(
  2262. bEnabled);
  2263. if (dwStatus != ERROR_SUCCESS)
  2264. {
  2265. return 0;
  2266. }
  2267. dwRetStatus = UPDATE_TERMSRV_SESSDIR;
  2268. }
  2269. if ((bExposeIP != s_fPreviousExposeIPState) && bEnabled)
  2270. {
  2271. DWORD dwStatus;
  2272. dwStatus = pCTssd->SetSessionDirectoryExposeIPState(
  2273. bExposeIP);
  2274. if (dwStatus != ERROR_SUCCESS)
  2275. {
  2276. return 0;
  2277. }
  2278. dwRetStatus = UPDATE_TERMSRV_SESSDIR;
  2279. }
  2280. if (s_fServerNameChanged || s_fClusterNameChanged || s_fRedirectIPChanged)
  2281. {
  2282. HKEY hKey;
  2283. TCHAR szTrim[] = TEXT( " " );
  2284. LONG lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2285. REG_TS_CLUSTERSETTINGS,
  2286. 0,
  2287. KEY_READ | KEY_WRITE,
  2288. &hKey);
  2289. if (lRet == ERROR_SUCCESS)
  2290. {
  2291. TCHAR szName[64];
  2292. if (s_fServerNameChanged)
  2293. {
  2294. BOOL fRet = FALSE;
  2295. GetWindowText( GetDlgItem( hwnd , IDC_EDIT_SERVERNAME ) ,
  2296. szName ,
  2297. sizeof( szName ) / sizeof( TCHAR ) );
  2298. //
  2299. // remove trailing spaces
  2300. //
  2301. StrTrim( szName , szTrim );
  2302. if( lstrlen( szName ) != 0 )
  2303. {
  2304. fRet = IsServerNameValid( szName , &dwRetStatus );
  2305. if( !fRet || dwRetStatus != ERROR_SUCCESS )
  2306. {
  2307. int nRet;
  2308. TCHAR szError[1024];
  2309. TCHAR szTitle[80];
  2310. TRC1((TB,"Server name was not valid"));
  2311. if( dwRetStatus != ERROR_SUCCESS )
  2312. {
  2313. LoadString( g_hInstance ,
  2314. IDS_ERROR_SDVERIFY,
  2315. szError,
  2316. sizeof(szError)/sizeof(TCHAR));
  2317. }
  2318. else
  2319. {
  2320. LoadString(g_hInstance,
  2321. IDS_ERROR_SDIRLOC,
  2322. szError,
  2323. sizeof(szError)/sizeof(TCHAR));
  2324. }
  2325. LoadString(g_hInstance,
  2326. IDS_ERROR_TITLE,
  2327. szTitle,
  2328. sizeof(szTitle)/sizeof(TCHAR));
  2329. nRet = MessageBox(hwnd, szError, szTitle,
  2330. MB_YESNO | MB_ICONWARNING);
  2331. if (nRet == IDNO)
  2332. {
  2333. SetFocus(GetDlgItem(hwnd,
  2334. IDC_EDIT_SERVERNAME));
  2335. SendMessage( GetDlgItem( hwnd , IDC_EDIT_SERVERNAME ) ,
  2336. EM_SETSEL ,
  2337. ( WPARAM )0,
  2338. ( LPARAM )-1 );
  2339. bEnabled = s_fPreviousButtonState;
  2340. pCTssd->SetSessionDirectoryEnabledState(bEnabled);
  2341. return 0;
  2342. }
  2343. }
  2344. }
  2345. else {
  2346. // Blank name not allowed if session directory
  2347. // is enabled. This code will not be run if the
  2348. // checkbox is disabled because when it is
  2349. // disabled the static flags get set to
  2350. // disabled.
  2351. TCHAR szError[256];
  2352. TCHAR szTitle[80];
  2353. LoadString(g_hInstance, IDS_ERROR_TITLE,
  2354. szTitle, sizeof(szTitle) /
  2355. sizeof(TCHAR));
  2356. LoadString(g_hInstance, IDS_ERROR_SDIREMPTY,
  2357. szError, sizeof(szError) /
  2358. sizeof(TCHAR));
  2359. MessageBox(hwnd, szError, szTitle,
  2360. MB_OK | MB_ICONWARNING);
  2361. SetFocus(GetDlgItem(hwnd,
  2362. IDC_EDIT_SERVERNAME));
  2363. bEnabled = s_fPreviousButtonState;
  2364. pCTssd->SetSessionDirectoryEnabledState(bEnabled);
  2365. return 0;
  2366. }
  2367. RegSetValueEx(hKey,
  2368. REG_TS_CLUSTER_STORESERVERNAME,
  2369. 0,
  2370. REG_SZ,
  2371. (CONST LPBYTE) szName,
  2372. sizeof(szName) - sizeof(TCHAR));
  2373. }
  2374. if (s_fClusterNameChanged)
  2375. {
  2376. GetWindowText(GetDlgItem(hwnd,
  2377. IDC_EDIT_CLUSTERNAME), szName,
  2378. sizeof(szName) / sizeof(TCHAR));
  2379. StrTrim( szName , szTrim );
  2380. RegSetValueEx(hKey,
  2381. REG_TS_CLUSTER_CLUSTERNAME,
  2382. 0,
  2383. REG_SZ,
  2384. (CONST LPBYTE) szName,
  2385. sizeof(szName) - sizeof(TCHAR));
  2386. }
  2387. if (s_fRedirectIPChanged)
  2388. {
  2389. HWND hComboBox;
  2390. LRESULT lRes;
  2391. LRESULT lLen;
  2392. LPWSTR pwszSel = NULL;
  2393. size_t dwSelPos;
  2394. // get handle to Combo Box
  2395. hComboBox = GetDlgItem(hwnd, IDC_IPCOMBO);
  2396. // get current selection position
  2397. lRes = SendMessage(hComboBox,
  2398. CB_GETCURSEL,
  2399. 0,
  2400. 0);
  2401. // get length of string stored at current selection
  2402. lLen = SendMessage(hComboBox,
  2403. CB_GETLBTEXTLEN,
  2404. (WPARAM)lRes,
  2405. 0);
  2406. if (lLen > 0)
  2407. {
  2408. // allocate room for selection string
  2409. pwszSel = (LPWSTR)GlobalAlloc(GPTR,
  2410. (lLen + 1) * sizeof(WCHAR));
  2411. if (pwszSel != NULL)
  2412. {
  2413. SendMessage(hComboBox,
  2414. CB_GETLBTEXT,
  2415. (WPARAM)lRes,
  2416. (LPARAM)pwszSel);
  2417. // we only want to store the IP address,
  2418. // however the string is returned in the
  2419. // form "IP Address (adapter)", so we'll
  2420. // extract IP first
  2421. // traverse the string until we find the
  2422. // first space
  2423. dwSelPos = 0;
  2424. // walk the string until we find the first
  2425. // space or we reach the end
  2426. while ( ( pwszSel[dwSelPos] != L' ' ) &&
  2427. ( dwSelPos < wcslen(pwszSel) ) )
  2428. {
  2429. dwSelPos++;
  2430. }
  2431. // for a match we know that there must be a
  2432. // space followed by an open bracket lets
  2433. // verify
  2434. if ( (dwSelPos < (wcslen(pwszSel) - 1)) &&
  2435. (pwszSel[dwSelPos + 1] == L'(') )
  2436. {
  2437. // set this char to NULL
  2438. pwszSel[dwSelPos] = L'\0';
  2439. // save new selection to registry
  2440. RegSetValueEx(hKey,
  2441. REG_TS_CLUSTER_REDIRECTIONIP,
  2442. 0,
  2443. REG_SZ,
  2444. (CONST LPBYTE) pwszSel,
  2445. (DWORD)(wcslen(pwszSel) *
  2446. sizeof(WCHAR)));
  2447. }
  2448. else
  2449. {
  2450. // store blank string
  2451. RegSetValueEx(hKey,
  2452. REG_TS_CLUSTER_REDIRECTIONIP,
  2453. 0,
  2454. REG_SZ,
  2455. (CONST LPBYTE) NULL,
  2456. 0);
  2457. }
  2458. GlobalFree(pwszSel);
  2459. }
  2460. }
  2461. }
  2462. RegCloseKey(hKey);
  2463. }
  2464. else
  2465. {
  2466. pCTssd->ErrorMessage(hwnd, IDS_ERROR_TEXT2,
  2467. (DWORD) lRet);
  2468. return 0;
  2469. }
  2470. dwRetStatus = UPDATE_TERMSRV_SESSDIR;
  2471. }
  2472. EndDialog(hwnd, dwRetStatus);
  2473. }
  2474. else
  2475. {
  2476. switch(HIWORD(wp))
  2477. {
  2478. case EN_CHANGE:
  2479. if (LOWORD(wp) == IDC_EDIT_SERVERNAME)
  2480. {
  2481. s_fServerNameChanged = TRUE;
  2482. }
  2483. else if (LOWORD(wp) == IDC_EDIT_CLUSTERNAME)
  2484. {
  2485. s_fClusterNameChanged = TRUE;
  2486. }
  2487. break;
  2488. case CBN_SELCHANGE:
  2489. if (LOWORD(wp) == IDC_IPCOMBO)
  2490. {
  2491. s_fRedirectIPChanged = TRUE;
  2492. }
  2493. break;
  2494. case BN_CLICKED:
  2495. if (LOWORD(wp) == IDC_CHECK_ENABLE)
  2496. {
  2497. BOOL bEnable;
  2498. bEnable = (IsDlgButtonChecked(hwnd, IDC_CHECK_ENABLE) ==
  2499. BST_CHECKED ? TRUE : FALSE);
  2500. // set flags
  2501. s_fServerNameChanged = bEnable;
  2502. s_fClusterNameChanged = bEnable;
  2503. s_fRedirectIPChanged = bEnable;
  2504. RegGetMachinePolicy(&gpolicy);
  2505. if (gpolicy.fPolicySessionDirectoryLocation)
  2506. {
  2507. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_SERVERNAME), FALSE);
  2508. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_STORENAME), FALSE);
  2509. }
  2510. else
  2511. {
  2512. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_SERVERNAME), bEnable);
  2513. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_STORENAME), bEnable);
  2514. }
  2515. if (gpolicy.fPolicySessionDirectoryClusterName)
  2516. {
  2517. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_CLUSTERNAME), FALSE);
  2518. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_CLUSTERNAME),FALSE);
  2519. }
  2520. else
  2521. {
  2522. EnableWindow(GetDlgItem(hwnd, IDC_EDIT_CLUSTERNAME), bEnable);
  2523. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_CLUSTERNAME),bEnable);
  2524. }
  2525. if (gpolicy.fPolicySessionDirectoryExposeServerIP != 0)
  2526. {
  2527. EnableWindow(GetDlgItem(hwnd, IDC_CHECK_EXPOSEIP), FALSE);
  2528. }
  2529. else
  2530. {
  2531. EnableWindow(GetDlgItem(hwnd, IDC_CHECK_EXPOSEIP), bEnable);
  2532. }
  2533. EnableWindow(GetDlgItem(hwnd, IDC_IPCOMBO), bEnable);
  2534. EnableWindow(GetDlgItem(hwnd, IDC_STATIC_IPCOMBO), bEnable);
  2535. }
  2536. break;
  2537. }
  2538. }
  2539. break;
  2540. }
  2541. return 0;
  2542. }
  2543. // When SD is restared, it will call this to ask for rejoining
  2544. DWORD TSSDRPCRejoinSD(handle_t Binding, DWORD flag)
  2545. {
  2546. Binding;
  2547. g_updatesd(flag); // This call is from SD computer, rejoin it
  2548. return RPC_S_OK;
  2549. }
  2550. /****************************************************************************/
  2551. // CheckRPCClientProtoSeq
  2552. //
  2553. // Check if the client uses the expected RPC protocol sequence or not
  2554. //
  2555. // Parameters:
  2556. // ClientBinding: The client binding handle
  2557. // SeqExpected: Protocol sequence expected
  2558. //
  2559. // Return:
  2560. // True on getting the expected seq, False otherwise
  2561. /****************************************************************************/
  2562. BOOL CheckRPCClientProtoSeq(void *ClientBinding, WCHAR *SeqExpected) {
  2563. BOOL fAllowProtocol = FALSE;
  2564. WCHAR *pBinding = NULL;
  2565. WCHAR *pProtSeq = NULL;
  2566. if (RpcBindingToStringBinding(ClientBinding,&pBinding) == RPC_S_OK) {
  2567. if (RpcStringBindingParse(pBinding,
  2568. NULL,
  2569. &pProtSeq,
  2570. NULL,
  2571. NULL,
  2572. NULL) == RPC_S_OK) {
  2573. // Check that the client request was made using expected protoal seq.
  2574. if (lstrcmpi(pProtSeq, SeqExpected) == 0)
  2575. fAllowProtocol = TRUE;
  2576. if (pProtSeq)
  2577. RpcStringFree(&pProtSeq);
  2578. }
  2579. if (pBinding)
  2580. RpcStringFree(&pBinding);
  2581. }
  2582. return fAllowProtocol;
  2583. }
  2584. /****************************************************************************/
  2585. // JetRpcAccessCheck
  2586. //
  2587. // Check if this RPC caller from SD havs access right or not
  2588. /****************************************************************************/
  2589. RPC_STATUS RPC_ENTRY JetRpcAccessCheck(RPC_IF_HANDLE idIF, void *Binding)
  2590. {
  2591. RPC_STATUS rpcStatus, rc;
  2592. HANDLE hClientToken = NULL;
  2593. DWORD Error;
  2594. BOOL AccessStatus = FALSE;
  2595. RPC_AUTHZ_HANDLE hPrivs;
  2596. DWORD dwAuthn;
  2597. idIF;
  2598. if (NULL == g_pSDSid) {
  2599. goto HandleError;
  2600. }
  2601. // Check if the client uses the protocol sequence we expect
  2602. if (!CheckRPCClientProtoSeq(Binding, L"ncacn_ip_tcp")) {
  2603. ERR((TB, "In JetRpcAccessCheck: Client doesn't use the tcpip protocol sequence\n"));
  2604. goto HandleError;
  2605. }
  2606. // Check what security level the client uses
  2607. rpcStatus = RpcBindingInqAuthClient(Binding,
  2608. &hPrivs,
  2609. NULL,
  2610. &dwAuthn,
  2611. NULL,
  2612. NULL);
  2613. if (rpcStatus != RPC_S_OK) {
  2614. ERR((TB, "In JetRpcAccessCheck: RpcBindingIngAuthClient fails with %u\n", rpcStatus));
  2615. goto HandleError;
  2616. }
  2617. // We request at least packet-level authentication
  2618. if (dwAuthn < RPC_C_AUTHN_LEVEL_PKT) {
  2619. ERR((TB, "In JetRpcAccessCheck: Attemp by client to use weak authentication\n"));
  2620. goto HandleError;
  2621. }
  2622. // Check the access right of this rpc call
  2623. rpcStatus = RpcImpersonateClient(Binding);
  2624. if (RPC_S_OK != rpcStatus) {
  2625. ERR((TB, "In JetRpcAccessCheck: RpcImpersonateClient fail with %u\n", rpcStatus));
  2626. goto HandleError;
  2627. }
  2628. // get our impersonated token
  2629. if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hClientToken)) {
  2630. Error = GetLastError();
  2631. ERR((TB, "In JetRpcAccessCheck: OpenThreadToken Error %u\n", Error));
  2632. RpcRevertToSelf();
  2633. goto HandleError;
  2634. }
  2635. RpcRevertToSelf();
  2636. if (!CheckTokenMembership(hClientToken,
  2637. g_pSDSid,
  2638. &AccessStatus)) {
  2639. AccessStatus = FALSE;
  2640. Error = GetLastError();
  2641. ERR((TB, "In JetRpcAccessCheck: CheckTokenMembership fails with %u\n", Error));
  2642. }
  2643. HandleError:
  2644. if (AccessStatus) {
  2645. rc = RPC_S_OK;
  2646. }
  2647. else {
  2648. rc = ERROR_ACCESS_DENIED;
  2649. }
  2650. if (hClientToken != NULL) {
  2651. CloseHandle(hClientToken);
  2652. }
  2653. return rc;
  2654. }
  2655. //*****************************************************************************
  2656. // Method:
  2657. // GetSDIPList
  2658. // Synopsis:
  2659. // Get a list of IP addresses that can be sued for Session Directory
  2660. // redirection. Omit IP address if it is the NLB IP address.
  2661. // Params:
  2662. // Out: pwszAddressList -- Array of WCHAR to receive IP address list
  2663. // In/Out: dwNumAddr -- In: Size of pwszAddressList array.
  2664. // Out: Number of IPs returned
  2665. // In: bIPAddress -- True: Get IPs. False: Get IPs + NIC names
  2666. // Return:
  2667. // HRESULT, S_OK is successful or other if failed
  2668. //*****************************************************************************
  2669. HRESULT GetSDIPList(WCHAR **pwszAddressList, DWORD *pdwNumAddr, BOOL bIPAddress)
  2670. {
  2671. DWORD dwCount = 0;
  2672. size_t cbSize = 0;
  2673. HRESULT hr = S_OK;
  2674. DWORD dwResult;
  2675. PIP_ADAPTER_INFO pAdapterInfo = NULL;
  2676. PIP_ADAPTER_INFO pAdapt;
  2677. PIP_ADDR_STRING pAddrStr;
  2678. ULONG ulAdapterInfoSize = 0;
  2679. WCHAR wszAddress[MAX_PATH] = L"";
  2680. WCHAR wszAdapterName[MAX_PATH] = L"";
  2681. LPWSTR pwszNLBipAddress = NULL;
  2682. LPWSTR pwszAdapterIP = NULL;
  2683. LPWSTR pwszMatch;
  2684. size_t dwAdapterIPLength;
  2685. LPWSTR pwszAdapterGUID = NULL;
  2686. LPTSTR astrLanaGUIDList[256] = { 0 }; // This will hold 256 adapter cards
  2687. DWORD dwLanaGUIDCount = 0;
  2688. DWORD i;
  2689. BOOL bAdapterFound = FALSE;
  2690. BOOL bAllAdaptersSet = FALSE;
  2691. // get the NLB IP address if it exists
  2692. hr = GetNLBIP(&pwszNLBipAddress);
  2693. if (FAILED(hr))
  2694. {
  2695. goto Cleanup;
  2696. }
  2697. // Get list of adapters used in ALL Winstations
  2698. hr = BuildLanaGUIDList(astrLanaGUIDList, &dwLanaGUIDCount);
  2699. if (FAILED(hr))
  2700. {
  2701. ERR((TB, "BuildLanaGUIDList fails with 0x%x", hr));
  2702. goto Cleanup;
  2703. }
  2704. // if a winstation has "All Network Adapters set...", then we will display
  2705. // all the adapters
  2706. if (hr == S_ALL_ADAPTERS_SET)
  2707. {
  2708. bAllAdaptersSet = TRUE;
  2709. }
  2710. // enumerate all of the adapters
  2711. // get size of buffer required, to do this we pass in an empty
  2712. // buffer length and we expect ERROR_BUFFER_OVERFLOW with a returned
  2713. // required buffer size
  2714. dwResult = GetAdaptersInfo(NULL, &ulAdapterInfoSize);
  2715. if (dwResult != ERROR_BUFFER_OVERFLOW)
  2716. {
  2717. hr = E_FAIL;
  2718. goto Cleanup;
  2719. }
  2720. // allocate memory for the linked list of adapter info's
  2721. pAdapterInfo = (PIP_ADAPTER_INFO)GlobalAlloc(GPTR, ulAdapterInfoSize);
  2722. if (pAdapterInfo == NULL)
  2723. {
  2724. hr = E_OUTOFMEMORY;
  2725. goto Cleanup;
  2726. }
  2727. // get the Adapter list
  2728. // note: PIP_ADAPTER_INFO is a linked list of adapters
  2729. dwResult = GetAdaptersInfo(pAdapterInfo, &ulAdapterInfoSize);
  2730. if (dwResult != ERROR_SUCCESS)
  2731. {
  2732. hr = E_FAIL;
  2733. goto Cleanup;
  2734. }
  2735. // enumerate the list of adapters and their IP Address List
  2736. pAdapt = pAdapterInfo;
  2737. while(pAdapt)
  2738. {
  2739. // get the Adapter Name string
  2740. MultiByteToWideChar(GetACP(),
  2741. 0,
  2742. pAdapt->Description,
  2743. -1,
  2744. wszAdapterName,
  2745. MAX_PATH);
  2746. // if a winstation is configured with "all adapters set..." then
  2747. // we can skip checking if each adapter is used in a winstation or not
  2748. if (!bAllAdaptersSet)
  2749. {
  2750. // get the Adapter Service Name GUID
  2751. hr = GetAdapterServiceName(wszAdapterName, &pwszAdapterGUID);
  2752. if (SUCCEEDED(hr) && (pwszAdapterGUID != NULL))
  2753. {
  2754. // check if this adapter is used in a winstation
  2755. // we've already got a list of GUIDs used so compare to that
  2756. for (i=0; i < dwLanaGUIDCount; i++)
  2757. {
  2758. bAdapterFound = FALSE;
  2759. if (!wcscmp(pwszAdapterGUID, astrLanaGUIDList[i]))
  2760. {
  2761. bAdapterFound = TRUE;
  2762. break;
  2763. }
  2764. }
  2765. }
  2766. // free the memory GetADapterServiceName allocated
  2767. if (pwszAdapterGUID != NULL)
  2768. {
  2769. GlobalFree(pwszAdapterGUID);
  2770. pwszAdapterGUID = NULL;
  2771. }
  2772. // if the adapter was not found above that means it is not configured
  2773. // to a winstation so we don't want to add this adapter here
  2774. if (!bAdapterFound)
  2775. {
  2776. pAdapt = pAdapt->Next;
  2777. continue;
  2778. }
  2779. }
  2780. // enumerate the list of IP Addresses associated with the adapter
  2781. pAddrStr = &(pAdapt->IpAddressList);
  2782. while(pAddrStr)
  2783. {
  2784. // get the IP Address string
  2785. MultiByteToWideChar(GetACP(),
  2786. 0,
  2787. pAddrStr->IpAddress.String,
  2788. -1,
  2789. wszAddress,
  2790. MAX_PATH);
  2791. // check if the Adapter IP address is configured. If not it will
  2792. // be "0.0.0.0" and don't include in list
  2793. if (!wcscmp(wszAddress, UNCONFIGURED_IP_ADDRESS))
  2794. {
  2795. pAddrStr = pAddrStr->Next;
  2796. continue;
  2797. }
  2798. // concatenate the IP Address with the adapter name in the form
  2799. // "IP Address (Adapter)"
  2800. // calculate string length first and allocate heap memory
  2801. // add 4 extra chars for space, 2 brackets and terminating NULL
  2802. dwAdapterIPLength = wcslen(wszAdapterName) + wcslen(wszAddress) + 4;
  2803. pwszAdapterIP = (LPWSTR)GlobalAlloc(GPTR, dwAdapterIPLength *
  2804. sizeof(WCHAR));
  2805. if (pwszAdapterIP == NULL) {
  2806. hr = E_OUTOFMEMORY;
  2807. goto Cleanup;
  2808. }
  2809. wcscpy(pwszAdapterIP, wszAddress);
  2810. wcscat(pwszAdapterIP, L" (");
  2811. wcscat(pwszAdapterIP, wszAdapterName);
  2812. wcscat(pwszAdapterIP, L")");
  2813. pwszAdapterIP[dwAdapterIPLength - 1] = L'\0';
  2814. if (bIPAddress) {
  2815. cbSize = (wcslen(wszAddress) + 1) * sizeof(WCHAR);
  2816. pwszAddressList[dwCount] = (LPWSTR)LocalAlloc(LMEM_FIXED, cbSize);
  2817. }
  2818. else {
  2819. cbSize = (wcslen(pwszAdapterIP) + 1) * sizeof(WCHAR);
  2820. pwszAddressList[dwCount] = (LPWSTR)LocalAlloc(LMEM_FIXED, cbSize);
  2821. }
  2822. if (pwszAddressList[dwCount] == NULL) {
  2823. hr = E_OUTOFMEMORY;
  2824. goto Cleanup;
  2825. }
  2826. // add to list only if the IP address isn't the NLB CLUSER IP
  2827. if (pwszNLBipAddress != NULL)
  2828. {
  2829. // check if IP address is NBL Cluster IP, we'll check for a match
  2830. // if so we will omit from list
  2831. pwszMatch = wcsstr(pwszNLBipAddress, wszAddress);
  2832. if (pwszMatch == NULL)
  2833. {
  2834. if (bIPAddress) {
  2835. // Get IP address only
  2836. wcsncpy(pwszAddressList[dwCount], wszAddress, cbSize / sizeof(WCHAR));
  2837. }
  2838. else {
  2839. // Get IP address and adapter name
  2840. wcsncpy(pwszAddressList[dwCount], pwszAdapterIP, cbSize / sizeof(WCHAR));
  2841. }
  2842. dwCount++;
  2843. if (dwCount == *pdwNumAddr) {
  2844. hr = S_OK;
  2845. goto Cleanup;
  2846. }
  2847. }
  2848. }
  2849. else
  2850. {
  2851. if (bIPAddress) {
  2852. // Get IP address only
  2853. wcsncpy(pwszAddressList[dwCount], wszAddress, cbSize / sizeof(WCHAR));
  2854. }
  2855. else {
  2856. // Get IP address and adapter name
  2857. wcsncpy(pwszAddressList[dwCount], pwszAdapterIP, cbSize / sizeof(WCHAR));
  2858. }
  2859. dwCount++;
  2860. if (dwCount == *pdwNumAddr) {
  2861. hr = S_OK;
  2862. goto Cleanup;
  2863. }
  2864. }
  2865. pAddrStr = pAddrStr->Next;
  2866. }
  2867. pAdapt = pAdapt->Next;
  2868. }
  2869. *pdwNumAddr = dwCount;
  2870. hr = S_OK;
  2871. Cleanup:
  2872. if (pAdapterInfo)
  2873. GlobalFree(pAdapterInfo);
  2874. if (pwszAdapterIP)
  2875. GlobalFree(pwszAdapterIP);
  2876. if (pwszNLBipAddress)
  2877. GlobalFree(pwszNLBipAddress);
  2878. for (i=0; i < dwLanaGUIDCount; i++)
  2879. {
  2880. if (astrLanaGUIDList[i])
  2881. {
  2882. GlobalFree(astrLanaGUIDList[i]);
  2883. }
  2884. }
  2885. return hr;
  2886. }
  2887. //*****************************************************************************
  2888. // Method:
  2889. // QueryNetworkAdapterAndIPs
  2890. // Synopsis:
  2891. // Query the Adapters that are installed on the system and their
  2892. // correspoding IP addresses and populate the combo box with the
  2893. // selections. Omit IP address if it is the NLB IP address.
  2894. // Params:
  2895. // In: hComboBox, handle to combo box to receive Adapter/IP list
  2896. // Return:
  2897. // HRESULT, S_OK is successful or other if failed
  2898. //*****************************************************************************
  2899. HRESULT
  2900. QueryNetworkAdapterAndIPs(HWND hComboBox)
  2901. {
  2902. HRESULT hr = S_OK;
  2903. DWORD dwResult;
  2904. LPWSTR pwszMatch;
  2905. DWORD cbData = MAX_PATH;
  2906. WCHAR wszSetIP[MAX_PATH] = L"";
  2907. HKEY hKey;
  2908. int nNumIPsInComboBox = 0;
  2909. LPWSTR pwszSel = NULL;
  2910. size_t dwLen;
  2911. int nPos;
  2912. DWORD i;
  2913. WCHAR *pwszAddressList[SD_NUM_IP_ADDRESS];
  2914. DWORD dwNumAddr = SD_NUM_IP_ADDRESS;
  2915. if (hComboBox == NULL)
  2916. {
  2917. return E_INVALIDARG;
  2918. }
  2919. // clear contents of combo box
  2920. SendMessage(hComboBox, CB_RESETCONTENT, 0, 0);
  2921. for (i=0; i<dwNumAddr; i++) {
  2922. pwszAddressList[i] = NULL;
  2923. }
  2924. hr = GetSDIPList(pwszAddressList, &dwNumAddr, FALSE);
  2925. if ( hr != S_OK) {
  2926. ERR((TB, "GetSDIPList fails with 0x%x", hr));
  2927. goto Cleanup;
  2928. }
  2929. for (i=0; i<dwNumAddr; i++) {
  2930. SendMessage(hComboBox, CB_ADDSTRING, 0, (LPARAM)pwszAddressList[i]);
  2931. nNumIPsInComboBox++;
  2932. }
  2933. // set combo-box selection to first item in list
  2934. SendMessage(hComboBox, CB_SETCURSEL, 0, (LPARAM)0);
  2935. // read in stored selection from registry we will then select it from list
  2936. dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2937. REG_TS_CLUSTERSETTINGS,
  2938. 0,
  2939. KEY_READ,
  2940. &hKey);
  2941. if (dwResult == ERROR_SUCCESS)
  2942. {
  2943. RegQueryValueEx(hKey,
  2944. REG_TS_CLUSTER_REDIRECTIONIP,
  2945. NULL,
  2946. NULL,
  2947. (LPBYTE)wszSetIP,
  2948. &cbData);
  2949. RegCloseKey(hKey);
  2950. }
  2951. // if a string was loaded from registry search combo box for it and select
  2952. if (wcslen(wszSetIP) > 0)
  2953. {
  2954. for (nPos = 0; nPos < nNumIPsInComboBox; nPos++)
  2955. {
  2956. // get length of string stored at current position
  2957. dwLen = SendMessage(hComboBox,
  2958. CB_GETLBTEXTLEN,
  2959. (WPARAM)nPos,
  2960. 0);
  2961. if (dwLen > 0)
  2962. {
  2963. // allocate room for selection
  2964. pwszSel = (LPWSTR)GlobalAlloc(GPTR, (dwLen + 1) * sizeof(WCHAR));
  2965. if (pwszSel != NULL)
  2966. {
  2967. SendMessage(hComboBox,
  2968. CB_GETLBTEXT,
  2969. (WPARAM)nPos,
  2970. (LPARAM)pwszSel);
  2971. // if we got a string check if it contains the IP we loaded
  2972. // from the registry
  2973. if (wcslen(pwszSel) > 0)
  2974. {
  2975. pwszMatch = wcsstr(pwszSel, wszSetIP);
  2976. if (pwszMatch != NULL)
  2977. {
  2978. // it's a match, lets break out
  2979. GlobalFree(pwszSel);
  2980. break;
  2981. }
  2982. }
  2983. GlobalFree(pwszSel);
  2984. pwszSel = NULL;
  2985. }
  2986. }
  2987. }
  2988. // if a match was found set it as the current selection
  2989. if (nPos < nNumIPsInComboBox)
  2990. {
  2991. SendMessage(hComboBox, CB_SETCURSEL, (WPARAM)nPos, (LPARAM)0);
  2992. }
  2993. }
  2994. Cleanup:
  2995. for(i=0; i<dwNumAddr; i++) {
  2996. if (pwszAddressList[i] != NULL) {
  2997. LocalFree(pwszAddressList[i]);
  2998. }
  2999. }
  3000. return hr;
  3001. }
  3002. //*****************************************************************************
  3003. // Method:
  3004. // GetNLBIP
  3005. // Synopsis:
  3006. // Return the NLB IP Address if one exists. Otherwise a NULL string
  3007. // is returned.
  3008. // Params:
  3009. // Out: ppwszRetIP, pointer to string to get IP address, caller must
  3010. // free this when their done with it
  3011. // Return:
  3012. // HRESULT, S_OK is successful or other if failed
  3013. //*****************************************************************************
  3014. HRESULT
  3015. GetNLBIP(LPWSTR * ppwszRetIP)
  3016. {
  3017. HRESULT hr = S_OK;
  3018. IWbemLocator * pWbemLocator = NULL;
  3019. IWbemServices * pWbemServices = NULL;
  3020. IWbemClassObject * pWbemObj = NULL;
  3021. IEnumWbemClassObject * pWbemEnum = NULL;
  3022. BSTR bstrServer = NULL;
  3023. BSTR bstrNode = NULL;
  3024. BSTR bstrNameProperty = NULL;
  3025. ULONG uReturned;
  3026. VARIANT vtNLBNodeName;
  3027. size_t dwIPLength;
  3028. // make sure an empty buffer is passed in
  3029. if (*ppwszRetIP != NULL)
  3030. {
  3031. hr = E_INVALIDARG;
  3032. goto Cleanup;
  3033. }
  3034. // create an instance of the WMI Locator, need this to query WMI
  3035. hr = CoCreateInstance(CLSID_WbemLocator,
  3036. 0,
  3037. CLSCTX_INPROC_SERVER,
  3038. IID_IWbemLocator,
  3039. reinterpret_cast<void**>(&pWbemLocator));
  3040. if (FAILED(hr))
  3041. {
  3042. goto Cleanup;
  3043. }
  3044. // create a connection to WMI Namespace "root\\MicrosoftNLB";
  3045. bstrServer = SysAllocString(L"root\\MicrosoftNLB");
  3046. if (bstrServer == NULL)
  3047. {
  3048. hr = E_OUTOFMEMORY;
  3049. goto Cleanup;
  3050. }
  3051. hr = pWbemLocator->ConnectServer(bstrServer,
  3052. NULL,
  3053. NULL,
  3054. 0,
  3055. NULL,
  3056. 0,
  3057. 0,
  3058. &pWbemServices);
  3059. if (FAILED(hr))
  3060. {
  3061. // If WMI is not available we don't want to fail, so just return S_OK
  3062. if (hr == HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED))
  3063. {
  3064. hr = S_OK;
  3065. }
  3066. goto Cleanup;
  3067. }
  3068. // Set the proxy so that impersonation of the client occurs.
  3069. hr = CoSetProxyBlanket(pWbemServices,
  3070. RPC_C_AUTHN_WINNT,
  3071. RPC_C_AUTHZ_NONE,
  3072. NULL,
  3073. RPC_C_AUTHN_LEVEL_CALL,
  3074. RPC_C_IMP_LEVEL_IMPERSONATE,
  3075. NULL,
  3076. EOAC_NONE);
  3077. if (FAILED(hr))
  3078. {
  3079. goto Cleanup;
  3080. }
  3081. // get instance of MicrosoftNLB_NodeSetting, this is where we can get the
  3082. // IP Address for the Cluster IP through the "Name" property
  3083. bstrNode = SysAllocString(L"MicrosoftNLB_NodeSetting");
  3084. if (bstrNode == NULL)
  3085. {
  3086. hr = E_OUTOFMEMORY;
  3087. goto Cleanup;
  3088. }
  3089. hr = pWbemServices->CreateInstanceEnum(bstrNode,
  3090. WBEM_FLAG_RETURN_IMMEDIATELY,
  3091. NULL,
  3092. &pWbemEnum);
  3093. if (FAILED(hr))
  3094. {
  3095. goto Cleanup;
  3096. }
  3097. uReturned = 0;
  3098. // we only need to look at one instance to get the NLB IP Address
  3099. hr = pWbemEnum->Next(WBEM_INFINITE,
  3100. 1,
  3101. &pWbemObj,
  3102. &uReturned);
  3103. if (FAILED(hr))
  3104. {
  3105. // if NLB provider doesn't exist provider will fail to load
  3106. // this is ok so we'll return S_OK in this case
  3107. if (hr == WBEM_E_PROVIDER_LOAD_FAILURE)
  3108. {
  3109. hr = S_OK;
  3110. }
  3111. goto Cleanup;
  3112. }
  3113. // Nothing to enumerate.
  3114. if( hr == WBEM_S_FALSE && uReturned == 0 )
  3115. {
  3116. hr = S_OK;
  3117. goto Cleanup;
  3118. }
  3119. if( pWbemObj == NULL )
  3120. {
  3121. hr = E_UNEXPECTED;
  3122. goto Cleanup;
  3123. }
  3124. // query the "Name" property which holds the IP address we want
  3125. bstrNameProperty = SysAllocString(L"Name");
  3126. if (bstrNameProperty == NULL)
  3127. {
  3128. hr = E_OUTOFMEMORY;
  3129. goto Cleanup;
  3130. }
  3131. hr = pWbemObj->Get(bstrNameProperty,
  3132. 0,
  3133. &vtNLBNodeName,
  3134. NULL,
  3135. NULL);
  3136. if (FAILED(hr))
  3137. {
  3138. goto Cleanup;
  3139. }
  3140. // We should get a string back
  3141. if (vtNLBNodeName.vt != VT_BSTR)
  3142. {
  3143. hr = E_UNEXPECTED;
  3144. goto Cleanup;
  3145. }
  3146. // allocate memory for the return string, *** CALLER MUST FREE THIS ***
  3147. dwIPLength = wcslen(vtNLBNodeName.bstrVal) + 1;
  3148. *ppwszRetIP = (LPWSTR)GlobalAlloc(GPTR, dwIPLength * sizeof(WCHAR));
  3149. if (*ppwszRetIP == NULL)
  3150. {
  3151. hr = E_OUTOFMEMORY;
  3152. goto Cleanup;
  3153. }
  3154. // Copy the string into our return buffer
  3155. wcscpy(*ppwszRetIP, vtNLBNodeName.bstrVal);
  3156. (*ppwszRetIP)[dwIPLength - 1] = L'\0';
  3157. Cleanup:
  3158. if (pWbemLocator)
  3159. pWbemLocator->Release();
  3160. if (pWbemServices)
  3161. pWbemServices->Release();
  3162. if (pWbemEnum)
  3163. pWbemEnum->Release();
  3164. if (pWbemObj)
  3165. pWbemObj->Release();
  3166. if (bstrServer)
  3167. SysFreeString(bstrServer);
  3168. if (bstrNode)
  3169. SysFreeString(bstrNode);
  3170. if (bstrNameProperty)
  3171. SysFreeString(bstrNameProperty);
  3172. VariantClear(&vtNLBNodeName);
  3173. return hr;
  3174. }
  3175. //*****************************************************************************
  3176. // Method:
  3177. // GetAdapterServiceName
  3178. // Synopsis:
  3179. // Each NIC is given a Service Name which is a GUID. This method will
  3180. // query this service name for the adapter associated with the
  3181. // description passed in.
  3182. // Params:
  3183. // wszAdapterDesc (IN): Adapter description to look up in the registry
  3184. // ppwszServiceName (OUT): Service Name (or GUID)
  3185. //
  3186. // Return:
  3187. // HRESULT, S_OK is successful or other if failed
  3188. //*****************************************************************************
  3189. HRESULT
  3190. GetAdapterServiceName(LPWSTR wszAdapterDesc, LPWSTR * ppwszServiceName)
  3191. {
  3192. HRESULT hr = S_OK;
  3193. LONG lRet;
  3194. HKEY hKey = NULL;
  3195. HKEY hSubKey = NULL;
  3196. DWORD dwNetCardLength;
  3197. TCHAR tchNetCard[MAX_PATH];
  3198. WCHAR wszVal[MAX_PATH];
  3199. DWORD dwSize;
  3200. DWORD i;
  3201. // Open the NetworkCards registry key
  3202. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3203. NETCARDS_REG_NAME,
  3204. 0,
  3205. KEY_READ,
  3206. &hKey);
  3207. if (lRet != ERROR_SUCCESS)
  3208. {
  3209. hr = E_UNEXPECTED;
  3210. goto Cleanup;
  3211. }
  3212. // Enumerate the Network Cards list and extract the Service Name GUID
  3213. for (i = 0, lRet = ERROR_SUCCESS; lRet == ERROR_SUCCESS; i++)
  3214. {
  3215. // Get the Network Card key
  3216. dwNetCardLength = MAX_PATH;
  3217. lRet = RegEnumKeyEx(hKey,
  3218. i,
  3219. tchNetCard,
  3220. &dwNetCardLength,
  3221. NULL,
  3222. NULL,
  3223. NULL,
  3224. NULL);
  3225. if (lRet == ERROR_SUCCESS)
  3226. {
  3227. // Open the Network card key, if it fails go to the next one
  3228. lRet = RegOpenKeyEx(hKey,
  3229. tchNetCard,
  3230. 0,
  3231. KEY_READ,
  3232. &hSubKey);
  3233. if (lRet == ERROR_SUCCESS)
  3234. {
  3235. // Query the Description Value
  3236. dwSize = MAX_PATH;
  3237. lRet = RegQueryValueEx(hSubKey,
  3238. NETCARD_DESC_VALUE_NAME,
  3239. NULL,
  3240. NULL,
  3241. (LPBYTE) &wszVal,
  3242. &dwSize);
  3243. if ( (lRet == ERROR_SUCCESS) && (wszVal != NULL) )
  3244. {
  3245. // Check if this is the adapter we're looking for
  3246. if (!wcscmp(wszAdapterDesc, wszVal))
  3247. {
  3248. // Get GUID for this Lan adapter
  3249. dwSize = MAX_PATH;
  3250. lRet = RegQueryValueEx(hSubKey,
  3251. NETCARD_SERVICENAME_VALUE_NAME,
  3252. NULL,
  3253. NULL,
  3254. (LPBYTE) &wszVal,
  3255. &dwSize);
  3256. if ( (lRet == ERROR_SUCCESS) && (wszVal != NULL) )
  3257. {
  3258. // Return dwSize from RegQueryValueEx is in bytes
  3259. *ppwszServiceName = (LPWSTR)GlobalAlloc(GPTR,
  3260. (dwSize + 1) + sizeof(WCHAR));
  3261. if (*ppwszServiceName == NULL)
  3262. {
  3263. hr = E_OUTOFMEMORY;
  3264. goto Cleanup;
  3265. }
  3266. // Copy name over and return
  3267. wcscpy(*ppwszServiceName, wszVal);
  3268. goto Cleanup;
  3269. }
  3270. }
  3271. }
  3272. RegCloseKey(hSubKey);
  3273. hSubKey = NULL;
  3274. }
  3275. // Set to success for our for loop
  3276. lRet = ERROR_SUCCESS;
  3277. }
  3278. }
  3279. Cleanup:
  3280. if (hKey != NULL)
  3281. {
  3282. RegCloseKey(hKey);
  3283. }
  3284. if (hSubKey != NULL)
  3285. {
  3286. RegCloseKey(hSubKey);
  3287. }
  3288. return hr;
  3289. }
  3290. //*****************************************************************************
  3291. // Method:
  3292. // BuildLanaGUIDList
  3293. // Synopsis:
  3294. // Build an array of strings (GUIDs) that represent LAN Adapter card
  3295. // service names that are set in all winstations.
  3296. // Params:
  3297. // pastrLanaGUIDList (OUT): Pointer to array of LPWSTR's to get
  3298. // service name GUIDs
  3299. // dwLanaGUIDCount (OUT): Count of service names returned in array
  3300. //
  3301. // Return:
  3302. // HRESULT, S_OK is successful or other if failed
  3303. // One special case is if a winstation is set to "All Adapters ..."
  3304. // then we'll just return S_ALL_ADAPTERS_SET
  3305. //*****************************************************************************
  3306. HRESULT
  3307. BuildLanaGUIDList(LPWSTR * pastrLanaGUIDList, DWORD *dwLanaGUIDCount)
  3308. {
  3309. HRESULT hr = S_OK;
  3310. LONG lRet;
  3311. HKEY hKey = NULL;
  3312. HKEY hSubKey = NULL;
  3313. DWORD dwWinstaNameLength;
  3314. TCHAR tchWinstaName[MAX_PATH];
  3315. DWORD dwVal = 0;
  3316. DWORD dwSize;
  3317. DWORD i;
  3318. LPWSTR wszGUID = NULL;
  3319. DWORD dwIndex = 0;
  3320. // Open the winstation registry key
  3321. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3322. WINSTATION_REG_NAME,
  3323. 0,
  3324. KEY_READ,
  3325. &hKey);
  3326. if (lRet != ERROR_SUCCESS)
  3327. {
  3328. hr = E_UNEXPECTED;
  3329. goto Cleanup;
  3330. }
  3331. // Enumerate the winstation list and extract the Lan Adapter used for each
  3332. for (i = 0, lRet = ERROR_SUCCESS; lRet == ERROR_SUCCESS; i++)
  3333. {
  3334. // Get the winsstation name
  3335. dwWinstaNameLength = MAX_PATH;
  3336. lRet = RegEnumKeyEx(hKey,
  3337. i,
  3338. tchWinstaName,
  3339. &dwWinstaNameLength,
  3340. NULL,
  3341. NULL,
  3342. NULL,
  3343. NULL);
  3344. if (lRet == ERROR_SUCCESS)
  3345. {
  3346. // Open the winstation, if it fails: go to the next one
  3347. lRet = RegOpenKeyEx(hKey,
  3348. tchWinstaName,
  3349. 0,
  3350. KEY_READ,
  3351. &hSubKey);
  3352. if (lRet == ERROR_SUCCESS)
  3353. {
  3354. // Query the Lan Adapter ID set for this winstation
  3355. dwSize = sizeof(DWORD);
  3356. lRet = RegQueryValueEx(hSubKey,
  3357. WIN_LANADAPTER,
  3358. NULL,
  3359. NULL,
  3360. (LPBYTE) &dwVal,
  3361. &dwSize);
  3362. if (lRet == ERROR_SUCCESS)
  3363. {
  3364. // If we ever see a return of "0" this means
  3365. // all adapters are set, so lets return a special
  3366. // hresult here to use all adapters.
  3367. if (dwVal == 0)
  3368. {
  3369. hr = S_ALL_ADAPTERS_SET;
  3370. goto Cleanup;
  3371. }
  3372. // Get Lan Adapter GUID for this ID
  3373. wszGUID = NULL;
  3374. hr = GetLanAdapterGuidFromID(dwVal, &wszGUID);
  3375. if (FAILED(hr))
  3376. {
  3377. goto Cleanup;
  3378. }
  3379. if (wszGUID != NULL)
  3380. {
  3381. pastrLanaGUIDList[dwIndex] = wszGUID;
  3382. dwIndex++;
  3383. }
  3384. }
  3385. RegCloseKey(hSubKey);
  3386. hSubKey = NULL;
  3387. }
  3388. // our for loop requires lRet to be ERROR_SUCCESS to keep going
  3389. lRet = ERROR_SUCCESS;
  3390. }
  3391. }
  3392. *dwLanaGUIDCount = dwIndex;
  3393. Cleanup:
  3394. if (hKey != NULL)
  3395. {
  3396. RegCloseKey(hKey);
  3397. }
  3398. if (hSubKey != NULL)
  3399. {
  3400. RegCloseKey(hSubKey);
  3401. }
  3402. return hr;
  3403. }
  3404. //*****************************************************************************
  3405. // Method:
  3406. // GetLanAdapterGuidFromID
  3407. // Synopsis:
  3408. // Get the GUID (Service Name) associated with a LAN ID that
  3409. // the winstation stores, when set from tscc.msc
  3410. // Params:
  3411. // dwLanAdapterID (IN): ID of adapter to get GUID for
  3412. // ppszLanAdapterGUID (OUT): Returned GUID string associated with ID
  3413. //
  3414. // Return:
  3415. // HRESULT, S_OK is successful or other if failed
  3416. //*****************************************************************************
  3417. HRESULT
  3418. GetLanAdapterGuidFromID(DWORD dwLanAdapterID, LPWSTR * ppszLanAdapterGUID)
  3419. {
  3420. HRESULT hr = S_OK;
  3421. LONG lRet;
  3422. HKEY hKey = NULL;
  3423. HKEY hSubKey = NULL;
  3424. DWORD dwLanAdapterGuidLength;
  3425. TCHAR tchLanAdapterGuid[MAX_PATH];
  3426. DWORD dwVal = 0;
  3427. DWORD dwSize;
  3428. DWORD i;
  3429. // Open the winstation registry key
  3430. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3431. LANATABLE_REG_NAME,
  3432. 0,
  3433. KEY_READ,
  3434. &hKey);
  3435. if (lRet != ERROR_SUCCESS)
  3436. {
  3437. hr = E_UNEXPECTED;
  3438. goto Cleanup;
  3439. }
  3440. // Enumerate the list of lan adapter guids
  3441. for (i = 0, lRet = ERROR_SUCCESS; lRet == ERROR_SUCCESS; i++)
  3442. {
  3443. // Get the next lan adapter guid
  3444. dwLanAdapterGuidLength = MAX_PATH;
  3445. lRet = RegEnumKeyEx(hKey,
  3446. i,
  3447. tchLanAdapterGuid,
  3448. &dwLanAdapterGuidLength,
  3449. NULL,
  3450. NULL,
  3451. NULL,
  3452. NULL);
  3453. if (lRet == ERROR_SUCCESS)
  3454. {
  3455. // Open the next lan adapter guid, if it fails for any reason
  3456. // we'll skip to the next
  3457. lRet = RegOpenKeyEx(hKey,
  3458. tchLanAdapterGuid,
  3459. 0,
  3460. KEY_READ,
  3461. &hSubKey);
  3462. if (lRet == ERROR_SUCCESS)
  3463. {
  3464. // Query the Lan Adapter GUID for it's ID
  3465. dwSize = sizeof(DWORD);
  3466. lRet = RegQueryValueEx(hSubKey,
  3467. LANAID_REG_VALUE_NAME,
  3468. NULL,
  3469. NULL,
  3470. (LPBYTE) &dwVal,
  3471. &dwSize);
  3472. if (lRet == ERROR_SUCCESS)
  3473. {
  3474. // Check if this is the guid we're looking for
  3475. if (dwVal == dwLanAdapterID)
  3476. {
  3477. // Copy GUID string to be returned and return
  3478. *ppszLanAdapterGUID = (LPWSTR)GlobalAlloc(GPTR,
  3479. (dwLanAdapterGuidLength + 1) * sizeof(WCHAR));
  3480. if (*ppszLanAdapterGUID == NULL)
  3481. {
  3482. hr = E_OUTOFMEMORY;
  3483. goto Cleanup;
  3484. }
  3485. wcscpy(*ppszLanAdapterGUID, tchLanAdapterGuid);
  3486. goto Cleanup;
  3487. }
  3488. }
  3489. RegCloseKey(hSubKey);
  3490. hSubKey = NULL;
  3491. }
  3492. // need to set lRet to success for our for loop to continue
  3493. lRet = ERROR_SUCCESS;
  3494. }
  3495. }
  3496. Cleanup:
  3497. if (hKey != NULL)
  3498. {
  3499. RegCloseKey(hKey);
  3500. }
  3501. if (hSubKey != NULL)
  3502. {
  3503. RegCloseKey(hSubKey);
  3504. }
  3505. return hr;
  3506. }
  3507. #pragma warning (pop)