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.

818 lines
16 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1998
  3. All rights reserved.
  4. Module Name:
  5. dsinterf.hxx
  6. Abstract:
  7. Directory service interface
  8. Author:
  9. Steve Kiraly (SteveKi) 09-Sept-1996
  10. Revision History:
  11. --*/
  12. #include "precomp.hxx"
  13. #pragma hdrstop
  14. #include "dsinterf.hxx"
  15. /*++
  16. Name:
  17. TDirectoryService constructor.
  18. Description:
  19. TDirectoryService is a helper class for encapsulating DS
  20. related functions.
  21. Arguments:
  22. None.
  23. Return Value:
  24. Nothing, use bValid for class state check.
  25. --*/
  26. TDirectoryService::
  27. TDirectoryService(
  28. VOID
  29. ) : _bValid( FALSE )
  30. {
  31. DBGMSG( DBG_TRACE, ( "TDirectoryService::ctor\n" ) );
  32. //
  33. // We must initialize OLE for in each thread. In this
  34. // case we assume the user of this class only creates
  35. // one per thread.
  36. //
  37. HRESULT hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
  38. if( hr == S_OK || hr == S_FALSE )
  39. {
  40. _bValid = TRUE;
  41. }
  42. }
  43. /*++
  44. Name:
  45. ~TDirectoryService destructor
  46. Description:
  47. Destructs this class, all clean up code should be placed here.
  48. Arguments:
  49. None.
  50. Return Value:
  51. Nothing.
  52. --*/
  53. TDirectoryService::
  54. ~TDirectoryService(
  55. VOID
  56. )
  57. {
  58. DBGMSG( DBG_TRACE, ( "TDirectoryService::dtor.\n" ) );
  59. //
  60. // Coinitlize was only called if we had
  61. // a valid object.
  62. //
  63. if( _bValid )
  64. {
  65. //
  66. // Balance the CoInitialize.
  67. //
  68. CoUninitialize();
  69. }
  70. }
  71. /*++
  72. Name:
  73. bValid
  74. Description:
  75. Indicates if the class is valid.
  76. Arguments:
  77. None.
  78. Return Value:
  79. TRUE class is valid, FALSE class is in an invalid state.
  80. --*/
  81. BOOL
  82. TDirectoryService::
  83. bValid(
  84. VOID
  85. )
  86. {
  87. DBGMSG( DBG_TRACE, ( "TDirectoryService::bValid.\n" ) );
  88. //
  89. // This class is always valid.
  90. //
  91. return TRUE;
  92. }
  93. /*++
  94. Name:
  95. bGetDirectoryName
  96. Description:
  97. Retrives the directory display name from the shell, i.e. ds folder.
  98. Arguments:
  99. strName - refrence to string object where to return
  100. directory display name.
  101. Return Value:
  102. TRUE name returne, FALSE error occurred.
  103. --*/
  104. BOOL
  105. TDirectoryService::
  106. bGetDirectoryName(
  107. IN TString &strName
  108. )
  109. {
  110. TStatusB bStatus;
  111. if( _strDirectoryName.bEmpty() )
  112. {
  113. TLibrary Lib( TEXT("dsuiext.dll") );
  114. if( VALID_OBJ( Lib ) )
  115. {
  116. typedef HRESULT (WINAPI *PF_FORMATDIRECTORYNAME)( LPTSTR *, PVOID, UINT );
  117. typedef VOID (WINAPI *PF_LOCALFREESTRING)( LPTSTR * );
  118. PF_FORMATDIRECTORYNAME pfFormatDirectoryName = (PF_FORMATDIRECTORYNAME)Lib.pfnGetProc( 578 );
  119. PF_LOCALFREESTRING pfLocalFreeString = (PF_LOCALFREESTRING)Lib.pfnGetProc( 542 );
  120. if( pfFormatDirectoryName && pfLocalFreeString )
  121. {
  122. HRESULT hr;
  123. LPTSTR pName = NULL;
  124. hr = pfFormatDirectoryName( &pName, NULL, 0 );
  125. if ( SUCCEEDED(hr) )
  126. {
  127. bStatus DBGCHK = _strDirectoryName.bUpdate( pName );
  128. pfLocalFreeString(&pName);
  129. }
  130. }
  131. }
  132. }
  133. //
  134. // If the directory name is empty indicate we cannot
  135. // get the directory name.
  136. //
  137. if( _strDirectoryName.bEmpty() )
  138. {
  139. bStatus DBGNOCHK = FALSE;
  140. }
  141. else
  142. {
  143. //
  144. // Return the directory name.
  145. //
  146. bStatus DBGCHK = strName.bUpdate( _strDirectoryName );
  147. }
  148. return bStatus;
  149. }
  150. /*++
  151. Name:
  152. bIsDsAvailable
  153. Description:
  154. Indicates if the directory service is available either for the
  155. user or from the machines perspective.
  156. Arguments:
  157. pName - pointer to a machine name, i.e. this call is remoteable.
  158. bForUser - TRUE indicate it is a user check, FALSE for machine.
  159. Return Value:
  160. TRUE if directory is available, otherwize false.
  161. --*/
  162. BOOL
  163. TDirectoryService::
  164. bIsDsAvailable(
  165. IN LPCTSTR pName,
  166. IN BOOL bForUser
  167. )
  168. {
  169. BOOL bReturn = FALSE;
  170. DWORD dwStatus = ERROR_SUCCESS;
  171. DWORD dwAccess = SERVER_READ;
  172. DWORD dwDsStatus = 0;
  173. HANDLE hServer = NULL;
  174. //
  175. // Open the server for read access.
  176. //
  177. dwStatus = TPrinter::sOpenPrinter( pName, &dwAccess, &hServer );
  178. //
  179. // If server handle opened.
  180. //
  181. if( dwStatus == ERROR_SUCCESS )
  182. {
  183. DWORD dwNeeded = 0;
  184. DWORD dwDsStatusType = REG_DWORD;
  185. if( dwStatus == ERROR_SUCCESS )
  186. {
  187. //
  188. // If the request for user or for machine.
  189. //
  190. LPTSTR pszKey = bForUser ? SPLREG_DS_PRESENT_FOR_USER : SPLREG_DS_PRESENT;
  191. //
  192. // Get the printer data key which indicates the DS is available.
  193. //
  194. dwStatus = GetPrinterData( hServer,
  195. pszKey,
  196. &dwDsStatusType,
  197. (PBYTE)&dwDsStatus,
  198. sizeof( dwDsStatus ),
  199. &dwNeeded );
  200. }
  201. if( dwStatus == ERROR_SUCCESS )
  202. {
  203. bReturn = dwDsStatus;
  204. }
  205. }
  206. //
  207. // Close the server handle.
  208. //
  209. if( hServer )
  210. {
  211. ClosePrinter( hServer );
  212. }
  213. return bReturn;
  214. }
  215. /*++
  216. Name:
  217. bIsDsAvailable
  218. Description:
  219. Indicates if the directory service is available either for the
  220. using the same check the shell uses.
  221. Arguments:
  222. None.
  223. Return Value:
  224. TRUE if directory is available, otherwize false.
  225. --*/
  226. BOOL
  227. TDirectoryService::
  228. bIsDsAvailable(
  229. VOID
  230. )
  231. {
  232. DBGMSG( DBG_TRACE, ( "TDirectoryService::bIsDsAvailble - ShowDirectoryUI.\n" ) );
  233. BOOL bStatus = FALSE;
  234. TLibrary Lib( TEXT("dsuiext.dll") );
  235. if( VALID_OBJ( Lib ) )
  236. {
  237. typedef BOOL (WINAPI *PF_SHOWDIRECTORYUI)( VOID );
  238. PF_SHOWDIRECTORYUI pfShowDirectoryUI = (PF_SHOWDIRECTORYUI)Lib.pfnGetProc( 577 );
  239. if( pfShowDirectoryUI )
  240. {
  241. bStatus = pfShowDirectoryUI();
  242. }
  243. }
  244. return bStatus;
  245. }
  246. HRESULT
  247. TDirectoryService::
  248. ADsGetObject(
  249. IN LPWSTR lpszPathName,
  250. IN REFIID riid,
  251. IN OUT VOID **ppObject
  252. )
  253. {
  254. return ::ADsGetObject( lpszPathName, riid, ppObject );
  255. }
  256. HRESULT
  257. TDirectoryService::
  258. ADsBuildEnumerator(
  259. IADsContainer *pADsContainer,
  260. IEnumVARIANT **ppEnumVariant
  261. )
  262. {
  263. return ::ADsBuildEnumerator( pADsContainer, ppEnumVariant);
  264. }
  265. HRESULT
  266. TDirectoryService::
  267. ADsFreeEnumerator(
  268. IEnumVARIANT *pEnumVariant
  269. )
  270. {
  271. return ::ADsFreeEnumerator( pEnumVariant );
  272. }
  273. HRESULT
  274. TDirectoryService::
  275. ADsEnumerateNext(
  276. IEnumVARIANT *pEnumVariant,
  277. ULONG cElements,
  278. VARIANT FAR *pvar,
  279. ULONG FAR *pcElementsFetched
  280. )
  281. {
  282. return ::ADsEnumerateNext( pEnumVariant, cElements, pvar, pcElementsFetched);
  283. }
  284. /*++
  285. Name:
  286. Get
  287. Description:
  288. This routine gets a string value from the specified DS object using
  289. the specified property. A copy of the string is made and placed into
  290. the provided string object.
  291. Arguments:
  292. pDsObject - pointer to the DS object interface
  293. pszPropertyName - DS object property name
  294. strString - refrence to string object where to return string
  295. Return Value:
  296. TRUE string put successfully, FALSE error occurred.
  297. --*/
  298. BOOL
  299. TDirectoryService::
  300. Get(
  301. IN IADs *pDsObject,
  302. IN LPCTSTR pszPropertyName,
  303. IN TString &strString
  304. )
  305. {
  306. SPLASSERT( pDsObject );
  307. SPLASSERT( pszPropertyName );
  308. VARIANT var;
  309. VariantInit( &var );
  310. HRESULT hr = pDsObject->Get( const_cast<LPTSTR>( pszPropertyName ), &var );
  311. if( SUCCEEDED( hr ) && ( var.vt == VT_BSTR ) )
  312. {
  313. hr = strString.bUpdate( V_BSTR(&var) ) ? S_OK : E_FAIL;
  314. }
  315. VariantClear (&var);
  316. return SUCCEEDED( hr );
  317. }
  318. /*++
  319. Name:
  320. Put
  321. Description:
  322. This routine puts a string value on the specified DS object
  323. for the specified property. This routine does not make a copy
  324. of the string but places it into a variant that is inturn passed
  325. to Ads::Put method.
  326. Arguments:
  327. pDsObject - pointer to the DS object interface
  328. pszPropertyName - DS object property name
  329. pszString - string value to put
  330. Return Value:
  331. TRUE string put successfully, FALSE error occurred.
  332. --*/
  333. BOOL
  334. TDirectoryService::
  335. Put(
  336. IN IADs *pDsObject,
  337. IN LPCTSTR pszPropertyName,
  338. IN LPCTSTR pszString
  339. )
  340. {
  341. SPLASSERT( pDsObject );
  342. SPLASSERT( pszPropertyName );
  343. VARIANT var;
  344. HRESULT hr;
  345. VariantInit (&var);
  346. if( !pszString || !*pszString )
  347. {
  348. hr = pDsObject->PutEx( ADS_PROPERTY_CLEAR, const_cast<LPTSTR>( pszPropertyName ), var );
  349. }
  350. else
  351. {
  352. var.vt = VT_BSTR;
  353. var.bstrVal = const_cast<LPTSTR>( pszString );
  354. hr = pDsObject->Put( const_cast<LPTSTR>( pszPropertyName ), var );
  355. }
  356. if( SUCCEEDED( hr ) )
  357. {
  358. hr = pDsObject->SetInfo();
  359. if( FAILED(hr) && ( !pszString || !*pszString ) )
  360. {
  361. //
  362. // From our perspective if we fail to delete a property because it does not exist
  363. // the operation actually succeeded.
  364. //
  365. if( HRESULT_CODE(hr) == ERROR_DS_NO_ATTRIBUTE_OR_VALUE )
  366. {
  367. hr = S_OK;
  368. }
  369. }
  370. }
  371. var.bstrVal = NULL;
  372. VariantClear (&var);
  373. return SUCCEEDED(hr);
  374. }
  375. /*++
  376. Name:
  377. TReadStringProperty
  378. Description:
  379. This routine reads the specified string using the specified path
  380. and property name from the DS.
  381. Arguments:
  382. strString - refrence to class where to returned read string.
  383. Return Value:
  384. TRUE string was read, FALSE error occurred.
  385. Notes:
  386. --*/
  387. BOOL
  388. TDirectoryService::
  389. ReadStringProperty(
  390. IN LPCTSTR pszPath,
  391. IN LPCTSTR pszProperty,
  392. IN OUT TString &strString
  393. )
  394. {
  395. IADs *pADs;
  396. HRESULT hStatus;
  397. hStatus = ADsGetObject( const_cast<LPTSTR>( pszPath ), IID_IADs, (void **)&pADs);
  398. if (SUCCEEDED(hStatus))
  399. {
  400. VARIANT var;
  401. VariantInit(&var);
  402. hStatus = pADs->Get( const_cast<LPTSTR>( pszProperty ), &var);
  403. if (SUCCEEDED(hStatus))
  404. {
  405. hStatus = strString.bUpdate( V_BSTR(&var) ) ? S_OK : E_FAIL;
  406. }
  407. VariantClear (&var);
  408. pADs->Release();
  409. }
  410. if (FAILED(hStatus))
  411. {
  412. DBGMSG( DBG_TRACE, ("ReadStringProperty Path " TSTR " Property " TSTR " failed %x\n", pszPath, pszProperty, hStatus ) );
  413. }
  414. return SUCCEEDED(hStatus);
  415. }
  416. /*++
  417. Name:
  418. GetConfigurationContainer
  419. Description:
  420. This routine figures out the and returnes the path of the
  421. longged on DS's configuration containter.
  422. Arguments:
  423. strConfig - Refrence to a string where to return the configuration string.
  424. Return Value:
  425. TRUE configuration containter returned. FALSE error occurred.
  426. Notes:
  427. --*/
  428. BOOL
  429. TDirectoryService::
  430. GetConfigurationContainer(
  431. IN OUT TString &strConfig
  432. )
  433. {
  434. TStatusB bStatus;
  435. //
  436. // If we have not already read the configuration container
  437. // then read it now.
  438. //
  439. if (_strConfigurationContainer.bEmpty())
  440. {
  441. TString strRootDSE;
  442. TString strLDAPPrefix;
  443. bStatus DBGCHK = GetLDAPPrefix( strLDAPPrefix ) &&
  444. strRootDSE.bCat( strLDAPPrefix ) &&
  445. strRootDSE.bCat( gszRootDSE );
  446. if (bStatus)
  447. {
  448. bStatus DBGCHK = ReadStringProperty( strRootDSE, gszConfigurationNameingContext, _strConfigurationContainer );
  449. }
  450. }
  451. bStatus DBGCHK = strConfig.bUpdate( _strConfigurationContainer );
  452. DBGMSG( DBG_TRACE, ( "Configuration Container " TSTR ".\n", (LPCTSTR)strConfig ) );
  453. return bStatus;
  454. }
  455. /*++
  456. Name:
  457. GetDsName
  458. Description:
  459. Returns a the DS UNC name that can be used in the call to
  460. AddressToSiteNames.
  461. Arguments:
  462. strDsName - refrence to string where to return the Ds name.
  463. Return Value:
  464. TRUE success, FALSE error occurred.
  465. Notes:
  466. --*/
  467. BOOL
  468. TDirectoryService::
  469. GetDsName(
  470. IN TString &strDsName
  471. )
  472. {
  473. TString strDomainName;
  474. TStatusB bStatus;
  475. bStatus DBGCHK = GetDomainName( strDomainName );
  476. if (bStatus)
  477. {
  478. bStatus DBGCHK = strDsName.bUpdate( gszLeadingSlashes ) && strDsName.bCat( strDomainName );
  479. }
  480. return bStatus;
  481. }
  482. /*++
  483. Name:
  484. GetLDAPPrefix
  485. Description:
  486. Returns the correct LDAP prefix using fully qualified machine account
  487. domain name (example "LDAP://ntdev.microsoft.com/"
  488. Arguments:
  489. strLDAPPrefix - where to return The LDAP prefix (domain relative or
  490. fully qualified)
  491. Return Value:
  492. TRUE on success, FALSE othewise
  493. Notes:
  494. --*/
  495. BOOL
  496. TDirectoryService::
  497. GetLDAPPrefix(
  498. OUT TString &strLDAPPrefix
  499. )
  500. {
  501. TStatusB bStatus;
  502. bStatus DBGNOCHK = TRUE;
  503. if( !_strLDAPPrefix.uLen( ) )
  504. {
  505. TString strRootDSE;
  506. TString strConfig;
  507. bStatus DBGCHK = strRootDSE.bCat( gszLdapPrefix ) &&
  508. strRootDSE.bCat( gszRootDSE );
  509. if( bStatus )
  510. {
  511. //
  512. // We need to use fully qualified domain LDAP address
  513. //
  514. TString strDomainName;
  515. bStatus DBGCHK = GetDomainName( strDomainName );
  516. if( bStatus )
  517. {
  518. bStatus DBGCHK = _strLDAPPrefix.bUpdate( NULL ) &&
  519. _strLDAPPrefix.bCat( gszLdapPrefix ) &&
  520. _strLDAPPrefix.bCat( strDomainName ) &&
  521. _strLDAPPrefix.bCat( gszSlash );
  522. }
  523. }
  524. }
  525. if( !_strLDAPPrefix.uLen( ) || !bStatus )
  526. {
  527. bStatus DBGCHK = _strLDAPPrefix.bUpdate( gszLdapPrefix );
  528. }
  529. if( bStatus )
  530. {
  531. bStatus DBGCHK = strLDAPPrefix.bUpdate( _strLDAPPrefix );
  532. }
  533. return bStatus;
  534. }
  535. /*++
  536. Name:
  537. GetLDAPPrefixPerUser
  538. Description:
  539. Returns the correct LDAP prefix using fully qualified machine account
  540. domain name (example "LDAP://ntdev.microsoft.com/" if the user domain
  541. (the domain in which the user is logged on) doesn't have a DS, if the
  542. user domain has a DS then we are using domain relative prefix (i.e.
  543. "LDAP://").
  544. Arguments:
  545. strLDAPPrefix - where to return The LDAP prefix (domain relative or
  546. fully qualified)
  547. Return Value:
  548. TRUE on success, FALSE othewise
  549. Notes:
  550. --*/
  551. BOOL
  552. TDirectoryService::
  553. GetLDAPPrefixPerUser(
  554. OUT TString &strLDAPPrefix
  555. )
  556. {
  557. TStatusB bStatus;
  558. bStatus DBGNOCHK = TRUE;
  559. if( !_strLDAPPrefixPerUser.uLen( ) )
  560. {
  561. TString strRootDSE;
  562. TString strConfig;
  563. bStatus DBGCHK = strRootDSE.bCat( gszLdapPrefix ) &&
  564. strRootDSE.bCat( gszRootDSE );
  565. if( bStatus )
  566. {
  567. bStatus DBGCHK = ReadStringProperty( strRootDSE, gszConfigurationNameingContext, strConfig );
  568. if( bStatus )
  569. {
  570. //
  571. // We can use domain relative LDAP address
  572. //
  573. bStatus DBGCHK = _strLDAPPrefixPerUser.bUpdate( gszLdapPrefix );
  574. }
  575. else
  576. {
  577. //
  578. // We need to use fully qualified domain LDAP address
  579. //
  580. bStatus DBGCHK = GetLDAPPrefix (_strLDAPPrefixPerUser);
  581. }
  582. }
  583. }
  584. if( !_strLDAPPrefixPerUser.uLen( ) || !bStatus )
  585. {
  586. bStatus DBGCHK = _strLDAPPrefixPerUser.bUpdate( gszLdapPrefix );
  587. }
  588. if( bStatus )
  589. {
  590. bStatus DBGCHK = strLDAPPrefix.bUpdate( _strLDAPPrefixPerUser );
  591. }
  592. return bStatus;
  593. }