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.

675 lines
19 KiB

  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright(C) 1997-2001 Microsoft Corporation all rights reserved.
  4. //
  5. // Module: dsconnection.cpp
  6. //
  7. // Project: Everest
  8. //
  9. // Description: data store connection implementation
  10. //
  11. // Author: TLP
  12. //
  13. // When Who What
  14. // ---- --- ----
  15. // 4/6/98 TLP Original Version
  16. //
  17. ///////////////////////////////////////////////////////////////////////////
  18. #include "stdafx.h"
  19. #include "dsconnection.h"
  20. #include "sdo.h"
  21. #include <dsgetdc.h>
  22. #include <lmaccess.h>
  23. #include <lmapibuf.h>
  24. #include <winsock2.h>
  25. namespace
  26. {
  27. BOOL
  28. WINAPI
  29. IsComputerLocalEx(
  30. PCWSTR computerName,
  31. COMPUTER_NAME_FORMAT nameType
  32. ) throw ()
  33. {
  34. WCHAR buffer[256];
  35. DWORD nSize = sizeof(buffer)/sizeof(WCHAR);
  36. BOOL success = GetComputerNameEx(
  37. nameType,
  38. buffer,
  39. &nSize
  40. );
  41. return success && !_wcsicmp(buffer, computerName);
  42. }
  43. BOOL
  44. WINAPI
  45. IsComputerLocal(
  46. PCWSTR computerName
  47. ) throw ()
  48. {
  49. return IsComputerLocalEx(
  50. computerName,
  51. ComputerNameNetBIOS
  52. ) ||
  53. IsComputerLocalEx(
  54. computerName,
  55. ComputerNameDnsHostname
  56. ) ||
  57. IsComputerLocalEx(
  58. computerName,
  59. ComputerNameDnsFullyQualified
  60. ) ||
  61. IsComputerLocalEx(
  62. computerName,
  63. ComputerNamePhysicalNetBIOS
  64. ) ||
  65. IsComputerLocalEx(
  66. computerName,
  67. ComputerNamePhysicalDnsHostname
  68. ) ||
  69. IsComputerLocalEx(
  70. computerName,
  71. ComputerNamePhysicalDnsFullyQualified
  72. );
  73. }
  74. }
  75. ///////////////////////////////////////////////////////////////////////////
  76. CDsConnection::CDsConnection()
  77. : m_eState(DISCONNECTED),
  78. m_bIsRemoteServer(false),
  79. m_bIsMixedMode(false),
  80. m_bInitializedDS(false),
  81. m_pDSRoot(NULL),
  82. m_pDSRootObject(NULL),
  83. m_pDSRootContainer(NULL)
  84. {
  85. m_szServerName[0] = '\0';
  86. m_szConfigPath[0] = '\0';
  87. }
  88. ///////////////////////////////////////////////////////////////////////////
  89. CDsConnection::~CDsConnection()
  90. {
  91. _ASSERT( DISCONNECTED == m_eState );
  92. }
  93. ///////////////////////////////////////////////////////////////////////////
  94. bool CDsConnection::SetServerName(LPCWSTR lpszServerName, bool bLocal)
  95. {
  96. bool success = false;
  97. if ((lpszServerName != 0) && (*lpszServerName != L'\0'))
  98. {
  99. ////////
  100. // Caller wants a specific server.
  101. ////////
  102. // Strip any leading backslashes.
  103. lpszServerName += wcsspn(lpszServerName, L"\\");
  104. // Make sure the name will fit in our buffer.
  105. if (wcslen(lpszServerName) <= IAS_MAX_SERVER_NAME)
  106. {
  107. // Save the name ...
  108. wcscpy(m_szServerName, lpszServerName);
  109. // ... and determine if it's local or remote.
  110. m_bIsRemoteServer = !IsComputerLocal(m_szServerName);
  111. success = true;
  112. }
  113. }
  114. else if (bLocal)
  115. {
  116. ////////
  117. // Caller wants the local machine.
  118. ////////
  119. DWORD dwSize = IAS_MAX_SERVER_NAME + 1;
  120. GetComputerNameW(m_szServerName, &dwSize);
  121. m_bIsRemoteServer = false;
  122. success = true;
  123. }
  124. else
  125. {
  126. ////////
  127. // Caller wants a domain controller.
  128. ////////
  129. PDOMAIN_CONTROLLER_INFOW dci;
  130. DWORD error = DsGetDcNameW(
  131. NULL,
  132. NULL,
  133. NULL,
  134. NULL,
  135. DS_DIRECTORY_SERVICE_REQUIRED,
  136. &dci
  137. );
  138. if (!error && dci->DomainControllerName)
  139. {
  140. success = SetServerName(dci->DomainControllerName, false);
  141. NetApiBufferFree(dci);
  142. }
  143. }
  144. IASTracePrintf("INFO CDsConnection::SetServerName ServerName = %S \n"
  145. "m_szServerName = %S IsRemoteServer %d Success = %d\n",
  146. lpszServerName,
  147. m_szServerName,
  148. m_bIsRemoteServer,
  149. success);
  150. return success;
  151. }
  152. ///////////////////////////////////////////////////////////////////////////
  153. HRESULT CDsConnectionIAS::Connect(
  154. /*[in]*/ LPCWSTR lpszServerName,
  155. /*[in]*/ LPCWSTR lpszUserName,
  156. /*[in]*/ LPCWSTR lpszPassword
  157. )
  158. {
  159. HRESULT hr = E_FAIL;
  160. _ASSERT( DISCONNECTED == m_eState );
  161. if ( SetServerName(lpszServerName, true) )
  162. {
  163. m_eState = CONNECTED;
  164. hr = S_OK;
  165. }
  166. else
  167. {
  168. m_szServerName[0] = '\0';
  169. m_szConfigPath[0] = '\0';
  170. }
  171. return hr;
  172. }
  173. ///////////////////////////////////////////////////////////////////////////
  174. HRESULT CDsConnectionIAS::InitializeDS()
  175. {
  176. HRESULT hr = S_OK;
  177. WCHAR szConfigPathBuff[IAS_MAX_CONFIG_PATH + 16];
  178. _ASSERT( CONNECTED == m_eState );
  179. if ( ! m_bInitializedDS )
  180. {
  181. // Set the path to the IAS configuration database
  182. //
  183. hr = E_FAIL;
  184. if ( SetConfigPath() )
  185. {
  186. // Create and initialize the IAS data store
  187. //
  188. CComPtr<IDataStore2> pDSRoot;
  189. hr = CoCreateInstance(
  190. __uuidof(OleDBDataStore),
  191. NULL,
  192. CLSCTX_SERVER,
  193. __uuidof(IDataStore2),
  194. (void**)&pDSRoot
  195. );
  196. if ( SUCCEEDED(hr) )
  197. {
  198. // We need to give the object permission to impersonate us. There's
  199. // no reason to abort if this fails; we'll just try with the
  200. // existing blanket.
  201. CoSetProxyBlanket(
  202. pDSRoot,
  203. RPC_C_AUTHN_DEFAULT,
  204. RPC_C_AUTHZ_DEFAULT,
  205. COLE_DEFAULT_PRINCIPAL,
  206. RPC_C_AUTHN_LEVEL_DEFAULT,
  207. RPC_C_IMP_LEVEL_IMPERSONATE,
  208. NULL,
  209. EOAC_DEFAULT
  210. );
  211. wsprintf(
  212. szConfigPathBuff,
  213. TEXT("%s\\%s"),
  214. m_szConfigPath,
  215. IAS_CONFIG_DB_LOCATION
  216. );
  217. CComBSTR bstrConfigPath(szConfigPathBuff);
  218. if (!bstrConfigPath) { return E_OUTOFMEMORY; }
  219. hr = pDSRoot->Initialize(
  220. bstrConfigPath,
  221. NULL,
  222. NULL
  223. );
  224. if ( SUCCEEDED(hr) )
  225. {
  226. // Save references to the data store root object and root object container
  227. //
  228. CComPtr<IDataStoreObject> pDSRootObject;
  229. hr = pDSRoot->get_Root(&pDSRootObject);
  230. if ( SUCCEEDED(hr) )
  231. {
  232. CComPtr<IDataStoreContainer> pDSRootContainer;
  233. hr = pDSRootObject->QueryInterface(IID_IDataStoreContainer, (void**)&pDSRootContainer);
  234. if ( SUCCEEDED(hr) )
  235. {
  236. pDSRoot.p->AddRef();
  237. pDSRootObject.p->AddRef();
  238. pDSRootContainer.p->AddRef();
  239. m_pDSRoot = pDSRoot;
  240. m_pDSRootObject = pDSRootObject;
  241. m_pDSRootContainer = pDSRootContainer;
  242. m_bInitializedDS = true;
  243. }
  244. }
  245. if ( FAILED(hr) )
  246. pDSRoot->Shutdown();
  247. }
  248. }
  249. }
  250. }
  251. return hr;
  252. }
  253. ///////////////////////////////////////////////////////////////////////////
  254. void CDsConnectionIAS::Disconnect()
  255. {
  256. if ( m_pDSRootContainer )
  257. {
  258. m_pDSRootContainer->Release();
  259. m_pDSRootContainer = NULL;
  260. }
  261. if ( m_pDSRootObject )
  262. {
  263. m_pDSRootObject->Release();
  264. m_pDSRootObject = NULL;
  265. }
  266. if ( m_pDSRoot )
  267. {
  268. m_pDSRoot->Shutdown();
  269. m_pDSRoot->Release();
  270. m_pDSRoot = NULL;
  271. }
  272. m_szServerName[0] = '\0';
  273. m_szConfigPath[0] = '\0';
  274. m_eState = DISCONNECTED;
  275. }
  276. ///////////////////////////////////////////////////////////////////////////
  277. bool CDsConnectionIAS::SetConfigPath()
  278. {
  279. bool bReturn = false;
  280. DWORD dwSize = IAS_MAX_CONFIG_PATH;
  281. DWORD dwResult = ERROR_SUCCESS;
  282. HKEY hKeyRemote = HKEY_LOCAL_MACHINE;
  283. WCHAR *pColon;
  284. CRegKey IASKey;
  285. WCHAR szConfigPathBuff[IAS_MAX_CONFIG_PATH];
  286. if ( m_bIsRemoteServer )
  287. dwResult = RegConnectRegistry(m_szServerName, HKEY_LOCAL_MACHINE, &hKeyRemote);
  288. if ( ERROR_SUCCESS == dwResult )
  289. {
  290. // Open the IAS Service Key
  291. //
  292. dwResult = IASKey.Open(
  293. hKeyRemote,
  294. IAS_POLICY_REG_KEY,
  295. KEY_READ
  296. );
  297. if ( ERROR_SUCCESS == dwResult )
  298. {
  299. // Get the value of the "ProgramDir" registry entry
  300. //
  301. dwSize = IAS_MAX_CONFIG_PATH;
  302. dwResult = IASKey.QueryValue(
  303. szConfigPathBuff,
  304. (LPCTSTR)IAS_SERVICE_DIRECTORY,
  305. &dwSize
  306. );
  307. if ( ERROR_SUCCESS == dwResult )
  308. {
  309. // If remote machine then create a path to the admin share.
  310. // Otherwise assume we're using the configuration on the local machine
  311. //
  312. if ( m_bIsRemoteServer )
  313. {
  314. if ( IAS_MAX_CONFIG_PATH > lstrlen(m_szServerName) + dwSize )
  315. {
  316. // Replace "Drive:" with "Drive$"
  317. //
  318. pColon = wcsrchr(szConfigPathBuff, L':');
  319. if (pColon == NULL)
  320. {
  321. return false;
  322. }
  323. *pColon = L'$';
  324. // Add leading "\\"
  325. //
  326. wsprintf(
  327. m_szConfigPath,
  328. TEXT("\\\\%s\\%s"),
  329. m_szServerName,
  330. szConfigPathBuff
  331. );
  332. bReturn = true;
  333. }
  334. }
  335. else
  336. {
  337. lstrcpy(m_szConfigPath, szConfigPathBuff);
  338. bReturn = true;
  339. }
  340. }
  341. }
  342. }
  343. IASTracePrintf("INFO CDsConnectionIAS::SetConfigPath. m_szConfigPath= %S\n"
  344. ,m_szConfigPath);
  345. return bReturn;
  346. }
  347. ///////////////////////////////////////////////////////////////////////////
  348. HRESULT CDsConnectionAD::Connect(
  349. /*[in]*/ LPCWSTR lpszServerName,
  350. /*[in]*/ LPCWSTR lpszUserName,
  351. /*[in]*/ LPCWSTR lpszPassword
  352. )
  353. {
  354. HRESULT hr = E_FAIL;
  355. _ASSERT( DISCONNECTED == m_eState );
  356. if ( SetServerName(lpszServerName, false) )
  357. {
  358. m_eState = CONNECTED;
  359. hr = S_OK;
  360. }
  361. return hr;
  362. }
  363. ///////////////////////////////////////////////////////////////////////////
  364. HRESULT CDsConnectionAD::InitializeDS()
  365. {
  366. HRESULT hr = S_OK;
  367. _ASSERT( CONNECTED == m_eState );
  368. if ( ! m_bInitializedDS )
  369. {
  370. _variant_t vtConfigNamingContext;
  371. _variant_t vtDefaultNamingContext;
  372. // Get the naming contexts at the specified directory server
  373. //
  374. hr = GetNamingContexts(&vtConfigNamingContext, &vtDefaultNamingContext);
  375. if ( SUCCEEDED(hr) )
  376. {
  377. // Set the domain mode - mixed or native
  378. //
  379. hr = SetMode(&vtDefaultNamingContext);
  380. if ( SUCCEEDED(hr) )
  381. {
  382. // Get the path to the DS configuration information (policies & profiles)
  383. //
  384. hr = SetConfigPath(&vtConfigNamingContext);
  385. if ( SUCCEEDED(hr) )
  386. m_bInitializedDS = true;
  387. }
  388. }
  389. }
  390. return hr;
  391. }
  392. ///////////////////////////////////////////////////////////////////////////
  393. void CDsConnectionAD::Disconnect()
  394. {
  395. if ( m_pDSRootContainer )
  396. {
  397. m_pDSRootContainer->Release();
  398. m_pDSRootContainer = NULL;
  399. }
  400. if ( m_pDSRootObject )
  401. {
  402. m_pDSRootObject->Release();
  403. m_pDSRootObject = NULL;
  404. }
  405. if ( m_pDSRoot )
  406. {
  407. m_pDSRoot->Shutdown();
  408. m_pDSRoot->Release();
  409. m_pDSRoot = NULL;
  410. }
  411. m_eState = DISCONNECTED;
  412. m_szServerName[0] = '\0';
  413. m_szConfigPath[0] = '\0';
  414. }
  415. ///////////////////////////////////////////////////////////////////////////
  416. HRESULT CDsConnectionAD::GetNamingContexts(
  417. /*[out]*/ VARIANT* pvtConfigNamingContext,
  418. /*[out]*/ VARIANT* pvtDefaultNamingContext
  419. )
  420. {
  421. HRESULT hr = E_FAIL;
  422. DWORD dwLength;
  423. _bstr_t bstrNamingContext;
  424. WCHAR szRootDSE[MAX_PATH];
  425. // Check preconditons
  426. //
  427. _ASSERT( NULL != pvtConfigNamingContext && NULL != pvtDefaultNamingContext );
  428. dwLength = lstrlen(IAS_NTDS_LDAP_PROVIDER) +
  429. lstrlen(m_szServerName) +
  430. lstrlen(IAS_NTDS_ROOT_DSE);
  431. _ASSERT( MAX_PATH > dwLength );
  432. if ( MAX_PATH > dwLength )
  433. {
  434. wsprintf(
  435. szRootDSE,
  436. TEXT("%s%s/%s"),
  437. IAS_NTDS_LDAP_PROVIDER,
  438. m_szServerName,
  439. IAS_NTDS_ROOT_DSE
  440. );
  441. CComPtr<IDataStore2> pDS2;
  442. hr = CoCreateInstance(
  443. __uuidof(ADsDataStore),
  444. NULL,
  445. CLSCTX_INPROC_SERVER,
  446. IID_IDataStore2,
  447. (void**)&pDS2
  448. );
  449. if ( SUCCEEDED(hr) )
  450. {
  451. hr = pDS2->Initialize(
  452. szRootDSE,
  453. NULL,
  454. NULL
  455. );
  456. if ( SUCCEEDED(hr) )
  457. {
  458. CComPtr<IDataStoreObject> pRootDSE;
  459. hr = pDS2->get_Root(&pRootDSE);
  460. if ( SUCCEEDED(hr) )
  461. {
  462. _bstr_t bstrNamingContext = IAS_NTDS_CONFIG_NAMING_CONTEXT;
  463. hr = pRootDSE->GetValue(bstrNamingContext, pvtConfigNamingContext);
  464. if ( SUCCEEDED(hr) )
  465. {
  466. bstrNamingContext = IAS_NTDS_DEFAULT_NAMING_CONTEXT;
  467. hr = pRootDSE->GetValue(bstrNamingContext, pvtDefaultNamingContext);
  468. if ( FAILED(hr) )
  469. VariantClear(pvtConfigNamingContext);
  470. }
  471. }
  472. pDS2->Shutdown();
  473. }
  474. }
  475. }
  476. return hr;
  477. }
  478. ///////////////////////////////////////////////////////////////////////////
  479. HRESULT CDsConnectionAD::SetMode(
  480. /*[in]*/ VARIANT* pvtDefaultNamingContext
  481. )
  482. {
  483. HRESULT hr = E_FAIL;
  484. DWORD dwLength;
  485. WCHAR szPath[MAX_PATH + 1];
  486. // Set the mixed mode flag based on the value of the "ntMixedDomain" property
  487. //
  488. _ASSERT ( NULL != pvtDefaultNamingContext );
  489. dwLength = lstrlen(IAS_NTDS_LDAP_PROVIDER) +
  490. lstrlen(m_szServerName) +
  491. lstrlen(V_BSTR(pvtDefaultNamingContext));
  492. _ASSERT( dwLength < MAX_PATH );
  493. if ( dwLength < MAX_PATH )
  494. {
  495. wsprintf(
  496. szPath,
  497. TEXT("%s%s/%s"),
  498. IAS_NTDS_LDAP_PROVIDER,
  499. m_szServerName,
  500. V_BSTR(pvtDefaultNamingContext)
  501. );
  502. CComPtr<IDataStore2> pDS2;
  503. hr = CoCreateInstance(
  504. __uuidof(ADsDataStore),
  505. NULL,
  506. CLSCTX_INPROC_SERVER,
  507. IID_IDataStore2,
  508. (void**)&pDS2
  509. );
  510. if ( SUCCEEDED(hr) )
  511. {
  512. hr = pDS2->Initialize(
  513. szPath,
  514. NULL,
  515. NULL
  516. );
  517. if ( SUCCEEDED(hr) )
  518. {
  519. CComPtr<IDataStoreObject> pDefaultNamingContext;
  520. hr = pDS2->get_Root(&pDefaultNamingContext);
  521. if ( SUCCEEDED(hr) )
  522. {
  523. _variant_t vtMode;
  524. hr = pDefaultNamingContext->GetValue(IAS_NTDS_MIXED_MODE_FLAG, &vtMode);
  525. if ( SUCCEEDED(hr) )
  526. {
  527. if ( IAS_MIXED_MODE == V_I4(&vtMode) )
  528. m_bMixedMode = true;
  529. else
  530. m_bMixedMode = false;
  531. }
  532. }
  533. pDS2->Shutdown();
  534. }
  535. }
  536. }
  537. return hr;
  538. }
  539. ///////////////////////////////////////////////////////////////////////////
  540. HRESULT CDsConnectionAD::SetConfigPath(
  541. /*[in]*/ VARIANT* pvtConfigNamingContext
  542. )
  543. {
  544. HRESULT hr = E_FAIL;
  545. DWORD dwLength;
  546. WCHAR szPath[MAX_PATH + 1];
  547. // Set the root and root container for the IAS configuration information
  548. //
  549. _ASSERT ( NULL != pvtConfigNamingContext );
  550. dwLength = lstrlen(IAS_NTDS_LDAP_PROVIDER) +
  551. lstrlen(m_szServerName) +
  552. lstrlen(IAS_NTDS_COMMON_NAMES) +
  553. lstrlen(V_BSTR(pvtConfigNamingContext));
  554. _ASSERT( dwLength < MAX_PATH );
  555. if ( dwLength < MAX_PATH )
  556. {
  557. wsprintf(
  558. szPath,
  559. // TEXT("%s%s/%s%s"),
  560. TEXT("%s%s/%s"),
  561. IAS_NTDS_LDAP_PROVIDER,
  562. m_szServerName,
  563. //IAS_NTDS_COMMON_NAMES,
  564. V_BSTR(pvtConfigNamingContext)
  565. );
  566. CComPtr<IDataStore2> pDSRoot;
  567. hr = CoCreateInstance(
  568. __uuidof(ADsDataStore),
  569. NULL,
  570. CLSCTX_INPROC_SERVER,
  571. IID_IDataStore2,
  572. (void**)&pDSRoot
  573. );
  574. if ( SUCCEEDED(hr) )
  575. {
  576. hr = pDSRoot->Initialize(
  577. szPath,
  578. NULL,
  579. NULL
  580. );
  581. if ( SUCCEEDED(hr) )
  582. {
  583. CComPtr<IDataStoreObject> pDSRootObject;
  584. hr = pDSRoot->get_Root(&pDSRootObject);
  585. if ( SUCCEEDED(hr) )
  586. {
  587. CComPtr<IDataStoreContainer> pDSRootContainer;
  588. hr = pDSRootObject->QueryInterface(IID_IDataStoreContainer, (void**)&pDSRootContainer);
  589. if ( SUCCEEDED(hr) )
  590. {
  591. pDSRoot.p->AddRef();
  592. pDSRootObject.p->AddRef();
  593. pDSRootContainer.p->AddRef();
  594. m_pDSRoot = pDSRoot;
  595. m_pDSRootObject = pDSRootObject;
  596. m_pDSRootContainer = pDSRootContainer;
  597. }
  598. }
  599. if ( FAILED(hr) )
  600. pDSRoot->Shutdown();
  601. }
  602. }
  603. }
  604. return hr;
  605. }