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

1401 lines
36 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996
  5. //
  6. // File: getobj.cxx
  7. //
  8. // Contents: LDAP GetObject functionality
  9. //
  10. // History:
  11. //----------------------------------------------------------------------------
  12. #include "ldap.hxx"
  13. #pragma hdrstop
  14. DWORD
  15. GetDefaultLdapServer(
  16. LPWSTR Addresses[],
  17. LPDWORD Count,
  18. BOOL Verify,
  19. DWORD dwPort
  20. ) ;
  21. DWORD
  22. GetDefaultServer(
  23. DWORD dwPort,
  24. BOOL fVerify,
  25. LPWSTR szDomainDnsName,
  26. LPWSTR szServerName,
  27. BOOL fWriteable
  28. );
  29. LPWSTR gpszStickyServerName = NULL;
  30. LPWSTR gpszStickyDomainName = NULL;
  31. //
  32. // Dont do DsGetDCName with FORCE_DISCOVERY too frequently.
  33. // LastVerifyDefaultServer is uses to track tick count.
  34. //
  35. #define DC_NORETRY (1000 * 60 * 5)
  36. DWORD LastVerifyDefaultServer = 0 ;
  37. //+---------------------------------------------------------------------------
  38. // Function: GetObject
  39. //
  40. // Synopsis: Called by ResolvePathName to return an object
  41. //
  42. // Arguments: [LPTSTR szBuffer]
  43. // [LPVOID *ppObject]
  44. //
  45. // Returns: HRESULT
  46. //
  47. // Modifies: -
  48. //
  49. // History: 11-3-95 krishnag Created.
  50. //
  51. //----------------------------------------------------------------------------
  52. HRESULT
  53. GetServerBasedObject(
  54. LPWSTR szBuffer,
  55. POBJECTINFO pObjectInfo,
  56. CCredentials& Credentials,
  57. LPVOID * ppObject
  58. )
  59. {
  60. HRESULT hr = S_OK;
  61. TCHAR *pszLDAPServer = NULL;
  62. TCHAR *pszLDAPDn = NULL;
  63. TCHAR *pszParent = NULL;
  64. TCHAR *pszCommonName = NULL;
  65. TCHAR szNamespace[MAX_PATH];
  66. IADs *pADs = NULL;
  67. LPTSTR *aValues = NULL;
  68. LPTSTR *aValuesNamingContext = NULL;
  69. int nCount = 0;
  70. TCHAR *pszNewADsPath = NULL;
  71. LPWSTR pszNewADsParent = NULL;
  72. LPWSTR pszNewADsCommonName = NULL;
  73. LPWSTR pszNamingContext = NULL;
  74. TCHAR *pszLast = NULL;
  75. BOOL fVerify = FALSE ;
  76. DWORD dwPort = 0;
  77. ADS_LDP *ld = NULL;
  78. BOOL fGCDefaulted = FALSE;
  79. BOOL fNoDefaultNamingContext = FALSE;
  80. BOOL fFastBind = Credentials.GetAuthFlags() & ADS_FAST_BIND;
  81. //
  82. // Validate that this ADs pathname is to be processed by
  83. // us - as in the provider name is LDAP:
  84. //
  85. hr = ValidateProvider(pObjectInfo);
  86. BAIL_ON_FAILURE(hr);
  87. hr = ValidateObjectType(pObjectInfo);
  88. BAIL_ON_FAILURE(hr);
  89. // Get the namespace name
  90. wcscpy(szNamespace, pObjectInfo->NamespaceName);
  91. wcscat(szNamespace, L":");
  92. switch (pObjectInfo->ObjectType) {
  93. case TOKEN_NAMESPACE:
  94. //
  95. // This means that this is a namespace object;
  96. // instantiate the namespace object
  97. //
  98. hr = GetNamespaceObject(
  99. pObjectInfo,
  100. Credentials,
  101. ppObject
  102. );
  103. BAIL_ON_FAILURE(hr);
  104. break;
  105. case TOKEN_ROOTDSE:
  106. //
  107. // This means that this is a RootDSE object;
  108. // instantiate the RootDSE object
  109. //
  110. hr = GetRootDSEObject(
  111. pObjectInfo,
  112. Credentials,
  113. ppObject
  114. );
  115. BAIL_ON_FAILURE(hr);
  116. break;
  117. case TOKEN_SCHEMA:
  118. case TOKEN_CLASS:
  119. case TOKEN_PROPERTY:
  120. case TOKEN_SYNTAX:
  121. hr = GetSchemaObject(
  122. pObjectInfo,
  123. Credentials,
  124. pObjectInfo->PortNumber,
  125. ppObject
  126. );
  127. BAIL_ON_FAILURE(hr);
  128. break;
  129. default:
  130. hr = BuildLDAPPathFromADsPath2(
  131. szBuffer,
  132. &pszLDAPServer,
  133. &pszLDAPDn,
  134. &dwPort
  135. );
  136. hr = LdapOpenObject2(
  137. pszLDAPServer,
  138. NULL,
  139. NULL,
  140. &ld,
  141. Credentials,
  142. dwPort
  143. );
  144. BAIL_ON_FAILURE(hr);
  145. if ( pszLDAPDn == NULL ) {
  146. // If only server name is specified, we need to
  147. // find the root of the naming context...
  148. if (dwPort == USE_DEFAULT_GC_PORT) {
  149. pszNamingContext = NULL;
  150. fGCDefaulted = TRUE;
  151. } else {
  152. pszNamingContext = TEXT(LDAP_OPATT_DEFAULT_NAMING_CONTEXT);
  153. }
  154. // We already have an open connection so we can do
  155. // fast read to avoid looking up the bind cache.
  156. if (!fGCDefaulted ) {
  157. hr = LdapReadAttributeFast(
  158. ld,
  159. NULL, // the DN is that of the RootDSE
  160. pszNamingContext,
  161. &aValuesNamingContext,
  162. &nCount
  163. );
  164. if (SUCCEEDED(hr) && (nCount < 1)) {
  165. hr = HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE);
  166. }
  167. }
  168. //
  169. // If we fail reading the naming context then we need to continue
  170. // if the error was no attribute or value, set some flags
  171. //
  172. if (FAILED(hr)) {
  173. if ( hr != HRESULT_FROM_WIN32(ERROR_DS_SERVER_DOWN) ) {
  174. nCount = 1;
  175. pszNamingContext = NULL;
  176. hr = S_OK;
  177. fNoDefaultNamingContext = TRUE;
  178. fGCDefaulted = TRUE;
  179. }
  180. }
  181. BAIL_ON_FAILURE(hr);
  182. //
  183. // At this point we have either
  184. // 1) Valid defaultNamingContext and pszNamingContext
  185. // 2) Either a GC or a case where defaultNamingContext
  186. // is not available - essentially just a null dn
  187. //
  188. hr = BuildADsPathFromLDAPPath2(
  189. TRUE, //Server is Present
  190. szNamespace,
  191. pszLDAPServer,
  192. dwPort,
  193. pszNamingContext ?
  194. aValuesNamingContext[0] :
  195. TEXT(""),
  196. &pszNewADsPath
  197. );
  198. BAIL_ON_FAILURE(hr);
  199. hr = BuildADsParentPath(
  200. pszNewADsPath,
  201. &pszNewADsParent,
  202. &pszNewADsCommonName
  203. );
  204. BAIL_ON_FAILURE(hr);
  205. if (pszLDAPServer) {
  206. FreeADsStr(pszLDAPServer);
  207. pszLDAPServer = NULL;
  208. }
  209. if (pszLDAPDn) {
  210. FreeADsStr(pszLDAPDn);
  211. pszLDAPDn = NULL;
  212. }
  213. //
  214. // Put the info from the new path build above into the
  215. // various components - matters if we are dealing with
  216. // a valid defaultNanmingContext
  217. //
  218. hr = BuildLDAPPathFromADsPath2(
  219. pszNewADsPath,
  220. &pszLDAPServer,
  221. &pszLDAPDn,
  222. &dwPort
  223. );
  224. }
  225. nCount = 0;
  226. // At this point we have a valid DN
  227. // so we can go ahead and do the a fast read rather than
  228. // just a plain read to avoid the overhead of looking upt
  229. // the bindcache.
  230. if (!fGCDefaulted && !fFastBind) {
  231. hr = LdapReadAttributeFast(
  232. ld,
  233. pszLDAPDn,
  234. TEXT("objectClass"),
  235. &aValues,
  236. &nCount
  237. );
  238. BAIL_ON_FAILURE(hr);
  239. if (nCount == 0) {
  240. BAIL_ON_FAILURE(hr = E_ADS_BAD_PATHNAME);
  241. }
  242. }
  243. if (fGCDefaulted) {
  244. //
  245. // This is either GC://server, where we want to
  246. // set the object DN to null so that all
  247. // searches will yield correct results.
  248. // or the case of a server that did not have
  249. // a default naming context in the RootDSE
  250. //
  251. hr = CLDAPGenObject::CreateGenericObject(
  252. pszNewADsParent,
  253. pszNewADsCommonName,
  254. L"top",
  255. Credentials,
  256. ADS_OBJECT_BOUND,
  257. IID_IADs,
  258. (void **) &pADs
  259. );
  260. }
  261. else if (aValuesNamingContext ) {
  262. //
  263. // Need to create the object with new parent
  264. // and newADsCN
  265. //
  266. if (fFastBind) {
  267. hr = CLDAPGenObject::CreateGenericObject(
  268. pszNewADsParent,
  269. pszNewADsCommonName,
  270. L"top",
  271. Credentials,
  272. ADS_OBJECT_BOUND,
  273. IID_IADs,
  274. (void **) &pADs,
  275. fFastBind
  276. );
  277. } else {
  278. hr = CLDAPGenObject::CreateGenericObject(
  279. pszNewADsParent,
  280. pszNewADsCommonName,
  281. aValues,
  282. nCount,
  283. Credentials,
  284. ADS_OBJECT_BOUND,
  285. IID_IADs,
  286. (void **) &pADs,
  287. fFastBind
  288. );
  289. }
  290. } else {
  291. //
  292. // This is the default case where we build the info from
  293. // the data passed into GetObject call
  294. //
  295. hr = BuildADsParentPathFromObjectInfo2(
  296. pObjectInfo,
  297. &pszParent,
  298. &pszCommonName
  299. );
  300. BAIL_ON_FAILURE(hr);
  301. if (fFastBind) {
  302. hr = CLDAPGenObject::CreateGenericObject(
  303. pszParent,
  304. pszCommonName,
  305. L"top",
  306. Credentials,
  307. ADS_OBJECT_BOUND,
  308. IID_IADs,
  309. (void **) &pADs,
  310. fFastBind
  311. );
  312. } else {
  313. hr = CLDAPGenObject::CreateGenericObject(
  314. pszParent,
  315. pszCommonName,
  316. aValues,
  317. nCount,
  318. Credentials,
  319. ADS_OBJECT_BOUND,
  320. IID_IADs,
  321. (void **) &pADs,
  322. fFastBind
  323. );
  324. }
  325. }
  326. BAIL_ON_FAILURE(hr);
  327. //
  328. // InstantiateDerivedObject should add-ref this pointer for us.
  329. //
  330. hr = pADs->QueryInterface(
  331. IID_IUnknown,
  332. ppObject
  333. );
  334. BAIL_ON_FAILURE(hr);
  335. break;
  336. }
  337. error:
  338. if ( ld ){
  339. LdapCloseObject( ld );
  340. }
  341. if (pADs)
  342. pADs->Release();
  343. if ( aValuesNamingContext )
  344. LdapValueFree( aValuesNamingContext );
  345. if ( aValues )
  346. LdapValueFree( aValues );
  347. if ( pszLDAPServer )
  348. FreeADsStr( pszLDAPServer );
  349. if (pszLDAPDn) {
  350. FreeADsStr(pszLDAPDn);
  351. }
  352. if ( pszNewADsPath )
  353. FreeADsStr( pszNewADsPath );
  354. if (pszNewADsParent) {
  355. FreeADsStr(pszNewADsParent);
  356. }
  357. if (pszNewADsCommonName) {
  358. FreeADsStr(pszNewADsCommonName);
  359. }
  360. if ( pszParent )
  361. FreeADsStr( pszParent );
  362. if ( pszCommonName )
  363. FreeADsStr( pszCommonName );
  364. RRETURN(hr);
  365. }
  366. //+---------------------------------------------------------------------------
  367. // Function: GetNamespaceObject
  368. //
  369. // Synopsis: called by GetObject
  370. //
  371. // Arguments: [POBJECTINFO pObjectInfo]
  372. // [LPVOID * ppObject]
  373. //
  374. // Returns: HRESULT
  375. //
  376. // Modifies: -
  377. //
  378. // History: 11-3-95 krishnag Created.
  379. //
  380. //----------------------------------------------------------------------------
  381. HRESULT
  382. GetNamespaceObject(
  383. POBJECTINFO pObjectInfo,
  384. CCredentials& Credentials,
  385. LPVOID * ppObject
  386. )
  387. {
  388. HRESULT hr;
  389. WCHAR szNamespace[MAX_PATH];
  390. hr = ValidateNamespaceObject(
  391. pObjectInfo
  392. );
  393. BAIL_ON_FAILURE(hr);
  394. wsprintf(szNamespace,L"%s:", pObjectInfo->NamespaceName);
  395. hr = CLDAPNamespace::CreateNamespace(
  396. TEXT("ADs:"),
  397. szNamespace,
  398. Credentials,
  399. ADS_OBJECT_BOUND,
  400. IID_IUnknown,
  401. ppObject
  402. );
  403. error:
  404. RRETURN(hr);
  405. }
  406. //+---------------------------------------------------------------------------
  407. // Function: GetRootDSEObject
  408. //
  409. // Synopsis: called by GetObject
  410. //
  411. // Arguments: [POBJECTINFO pObjectInfo]
  412. // [LPVOID * ppObject]
  413. //
  414. // Returns: HRESULT
  415. //
  416. // Modifies: -
  417. //
  418. // History: 11-3-95 krishnag Created.
  419. //
  420. //----------------------------------------------------------------------------
  421. HRESULT
  422. GetRootDSEObject(
  423. POBJECTINFO pObjectInfo,
  424. CCredentials& Credentials,
  425. LPVOID * ppObject
  426. )
  427. {
  428. HRESULT hr;
  429. LPWSTR pszParent = NULL;
  430. LPWSTR pszCommonName = NULL;
  431. hr = ValidateRootDSEObject(
  432. pObjectInfo
  433. );
  434. BAIL_ON_FAILURE(hr);
  435. hr = BuildADsParentPathFromObjectInfo2(
  436. pObjectInfo,
  437. &pszParent,
  438. &pszCommonName
  439. );
  440. BAIL_ON_FAILURE(hr);
  441. hr = CLDAPRootDSE::CreateRootDSE(
  442. pszParent,
  443. pszCommonName,
  444. L"",
  445. Credentials,
  446. ADS_OBJECT_BOUND,
  447. IID_IUnknown,
  448. (void **)ppObject
  449. );
  450. error:
  451. if (pszParent) {
  452. FreeADsStr(pszParent);
  453. }
  454. if (pszCommonName) {
  455. FreeADsStr(pszCommonName);
  456. }
  457. RRETURN(hr);
  458. }
  459. HRESULT
  460. ValidateRootDSEObject(
  461. POBJECTINFO pObjectInfo
  462. )
  463. {
  464. if ( pObjectInfo->NumComponents > 1 )
  465. {
  466. RRETURN(E_ADS_BAD_PATHNAME);
  467. }
  468. RRETURN(S_OK);
  469. }
  470. HRESULT
  471. ValidateNamespaceObject(
  472. POBJECTINFO pObjectInfo
  473. )
  474. {
  475. if (_tcsicmp(pObjectInfo->NamespaceName, szLDAPNamespaceName) == 0 ||
  476. _tcsicmp(pObjectInfo->NamespaceName, szGCNamespaceName) == 0) {
  477. RRETURN(S_OK);
  478. }
  479. RRETURN(E_FAIL);
  480. }
  481. HRESULT
  482. ValidateProvider(
  483. POBJECTINFO pObjectInfo
  484. )
  485. {
  486. //
  487. // The provider name is case-sensitive. This is a restriction that OLE
  488. // has put on us.
  489. //
  490. if (_tcscmp(pObjectInfo->ProviderName, szProviderName) == 0) {
  491. RRETURN(S_OK);
  492. }
  493. RRETURN(E_FAIL);
  494. }
  495. //+---------------------------------------------------------------------------
  496. // Function: GetSchemaObject
  497. //
  498. // Synopsis: called by GetObject
  499. //
  500. // Arguments: [POBJECTINFO pObjectInfo]
  501. // [LPVOID * ppObject]
  502. //
  503. // Returns: HRESULT
  504. //
  505. // Modifies: -
  506. //
  507. // History: 11-3-95 krishnag Created.
  508. //
  509. //----------------------------------------------------------------------------
  510. HRESULT
  511. GetSchemaObject(
  512. POBJECTINFO pObjectInfo,
  513. CCredentials& Credentials,
  514. DWORD dwPort,
  515. LPVOID * ppObject
  516. )
  517. {
  518. HRESULT hr = S_OK;
  519. TCHAR szDomainName[MAX_PATH];
  520. TCHAR szServerName[MAX_PATH];
  521. TCHAR *pszParent = NULL;
  522. TCHAR *pszCommonName = NULL;
  523. DWORD dwObjectType = 0;
  524. DWORD i,dwStatus;
  525. LDAP_SCHEMA_HANDLE hSchema = NULL;
  526. BOOL fFound = FALSE;
  527. hr = ValidateSchemaObject(
  528. pObjectInfo,
  529. &dwObjectType
  530. );
  531. BAIL_ON_FAILURE(hr);
  532. if (pObjectInfo->TreeName) {
  533. _tcscpy(szDomainName, pObjectInfo->TreeName);
  534. }else {
  535. LPTSTR aAddresses[5];
  536. DWORD nCount = 5;
  537. BOOL fVerify = FALSE;
  538. dwStatus = GetDefaultServer(
  539. dwPort,
  540. fVerify,
  541. szDomainName,
  542. szServerName,
  543. TRUE
  544. );
  545. if (dwStatus) {
  546. hr = HRESULT_FROM_WIN32(dwStatus);
  547. BAIL_ON_FAILURE(hr);
  548. }
  549. }
  550. hr = SchemaOpen(
  551. szDomainName,
  552. &hSchema,
  553. Credentials,
  554. dwPort
  555. );
  556. BAIL_ON_FAILURE(hr);
  557. hr = BuildADsParentPathFromObjectInfo2(
  558. pObjectInfo,
  559. &pszParent,
  560. &pszCommonName
  561. );
  562. BAIL_ON_FAILURE(hr);
  563. switch (dwObjectType) {
  564. case LDAP_SCHEMA_ID:
  565. hr = CLDAPSchema::CreateSchema(
  566. pszParent,
  567. pszCommonName,
  568. szDomainName,
  569. Credentials,
  570. ADS_OBJECT_BOUND,
  571. IID_IUnknown,
  572. ppObject
  573. );
  574. BAIL_ON_FAILURE(hr);
  575. break;
  576. case LDAP_CLASS_ID:
  577. {
  578. CLASSINFO *pClassInfo = NULL;
  579. if ( pObjectInfo->NumComponents < 2 )
  580. {
  581. hr = E_ADS_BAD_PATHNAME;
  582. BAIL_ON_FAILURE(hr);
  583. }
  584. //
  585. // Look for the given class name
  586. //
  587. if (pObjectInfo->dwPathType == PATHTYPE_WINDOWS) {
  588. hr = SchemaGetClassInfo(
  589. hSchema,
  590. pObjectInfo->ComponentArray[1].szComponent,
  591. &pClassInfo );
  592. }else {
  593. hr = SchemaGetClassInfo(
  594. hSchema,
  595. pObjectInfo->ComponentArray[0].szComponent,
  596. &pClassInfo);
  597. }
  598. if ( SUCCEEDED(hr))
  599. {
  600. if ( pClassInfo == NULL ) // could not find the class name
  601. {
  602. // Do not bail on failure here since we might need to fall
  603. // through to the property case.
  604. hr = E_ADS_BAD_PATHNAME;
  605. }
  606. }
  607. if ( SUCCEEDED(hr))
  608. {
  609. //
  610. // Class name found, create and return the object
  611. //
  612. hr = CLDAPClass::CreateClass( pszParent,
  613. hSchema,
  614. pClassInfo->pszName,
  615. pClassInfo,
  616. Credentials,
  617. ADS_OBJECT_BOUND,
  618. IID_IUnknown,
  619. ppObject );
  620. }
  621. if ( SUCCEEDED(hr)
  622. || ( pObjectInfo->ObjectType == TOKEN_CLASS )
  623. )
  624. {
  625. BAIL_ON_FAILURE(hr);
  626. break;
  627. }
  628. hr = S_OK;
  629. // Else the exact type was not specified and we guessed it to be class
  630. // but since CreateClass failed, we need to try and see if it is a
  631. // property object. Hence, falls through
  632. }
  633. case LDAP_PROPERTY_ID:
  634. {
  635. PROPERTYINFO *pPropertyInfo = NULL;
  636. if ( pObjectInfo->NumComponents < 2)
  637. {
  638. hr = E_ADS_BAD_PATHNAME;
  639. BAIL_ON_FAILURE(hr);
  640. }
  641. //
  642. // Look for the given property name
  643. //
  644. if (pObjectInfo->dwPathType == PATHTYPE_WINDOWS) {
  645. hr = SchemaGetPropertyInfo(
  646. hSchema,
  647. pObjectInfo->ComponentArray[1].szComponent,
  648. &pPropertyInfo );
  649. }else{
  650. hr = SchemaGetPropertyInfo(
  651. hSchema,
  652. pObjectInfo->ComponentArray[0].szComponent,
  653. &pPropertyInfo
  654. );
  655. }
  656. if ( SUCCEEDED(hr))
  657. {
  658. if ( pPropertyInfo == NULL ) // could not find the property name
  659. {
  660. // Do not bail on failure here since we might need to fall
  661. // through to the syntax case.
  662. hr = E_ADS_BAD_PATHNAME;
  663. }
  664. }
  665. if ( SUCCEEDED(hr))
  666. {
  667. //
  668. // Property name found, so create and return the object
  669. //
  670. hr = CLDAPProperty::CreateProperty(
  671. pszParent,
  672. hSchema,
  673. pPropertyInfo->pszPropertyName,
  674. pPropertyInfo,
  675. Credentials,
  676. ADS_OBJECT_BOUND,
  677. IID_IUnknown,
  678. ppObject );
  679. }
  680. if ( SUCCEEDED(hr)
  681. || ( pObjectInfo->ObjectType == TOKEN_PROPERTY )
  682. )
  683. {
  684. BAIL_ON_FAILURE(hr);
  685. break;
  686. }
  687. hr = S_OK;
  688. // Else the exact type was not specified and we guessed it to be
  689. // property but since CreateProperty failed, we need to try and see if
  690. // it is a syntax object. Hence, falls through
  691. }
  692. case LDAP_SYNTAX_ID:
  693. if ( pObjectInfo->NumComponents < 2 )
  694. {
  695. hr = E_ADS_BAD_PATHNAME;
  696. BAIL_ON_FAILURE(hr);
  697. }
  698. //
  699. // Look for the given syntax name
  700. //
  701. for ( i = 0; i < g_cLDAPSyntax; i++ )
  702. {
  703. if ( _tcsicmp( g_aLDAPSyntax[i].pszName,
  704. (pObjectInfo->dwPathType == PATHTYPE_WINDOWS)?
  705. pObjectInfo->ComponentArray[1].szComponent:
  706. pObjectInfo->ComponentArray[0].szComponent ) == 0 )
  707. break;
  708. }
  709. if ( i == g_cLDAPSyntax )
  710. {
  711. hr = E_ADS_BAD_PATHNAME;
  712. BAIL_ON_FAILURE(hr);
  713. }
  714. //
  715. // Syntax name found, create and return the object
  716. //
  717. hr = CLDAPSyntax::CreateSyntax(
  718. pszParent,
  719. &(g_aLDAPSyntax[i]),
  720. Credentials,
  721. ADS_OBJECT_BOUND,
  722. IID_IUnknown,
  723. ppObject
  724. );
  725. BAIL_ON_FAILURE(hr);
  726. break;
  727. default:
  728. hr = E_ADS_UNKNOWN_OBJECT;
  729. break;
  730. }
  731. error:
  732. if ( pszParent )
  733. FreeADsStr( pszParent );
  734. if ( pszCommonName )
  735. FreeADsStr( pszCommonName );
  736. if ( hSchema )
  737. SchemaClose( &hSchema );
  738. RRETURN(hr);
  739. }
  740. HRESULT
  741. ValidateSchemaObject(
  742. POBJECTINFO pObjectInfo,
  743. PDWORD pdwObjectType
  744. )
  745. {
  746. DWORD dwNumComponents = 0;
  747. HRESULT hr = S_OK;
  748. switch ( pObjectInfo->ObjectType )
  749. {
  750. case TOKEN_CLASS:
  751. *pdwObjectType = LDAP_CLASS_ID;
  752. break;
  753. case TOKEN_SYNTAX:
  754. *pdwObjectType = LDAP_SYNTAX_ID;
  755. break;
  756. case TOKEN_PROPERTY:
  757. *pdwObjectType = LDAP_PROPERTY_ID;
  758. break;
  759. case TOKEN_SCHEMA:
  760. dwNumComponents = pObjectInfo->NumComponents;
  761. switch (dwNumComponents) {
  762. case 1:
  763. if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,
  764. SCHEMA_NAME))
  765. *pdwObjectType = LDAP_SCHEMA_ID;
  766. break;
  767. case 2:
  768. if (pObjectInfo->dwPathType == PATHTYPE_WINDOWS) {
  769. if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,
  770. SCHEMA_NAME))
  771. *pdwObjectType = LDAP_CLASS_ID;
  772. // Might also be a property or syntax object
  773. // see function GetSchemaObject()
  774. }else {
  775. if (!_tcsicmp(pObjectInfo->ComponentArray[dwNumComponents - 1].szComponent,
  776. SCHEMA_NAME))
  777. *pdwObjectType = LDAP_CLASS_ID;
  778. // Might also be a property or syntax object
  779. // see function GetSchemaObject()
  780. }
  781. break;
  782. default:
  783. hr = E_FAIL;
  784. break;
  785. }
  786. break;
  787. default:
  788. hr = E_FAIL;
  789. break;
  790. }
  791. RRETURN(hr);
  792. }
  793. HRESULT
  794. ValidateObjectType(
  795. POBJECTINFO pObjectInfo
  796. )
  797. {
  798. if ( pObjectInfo->ObjectType != TOKEN_LDAPOBJECT )
  799. {
  800. // The type has already been specified in this case using COMMA
  801. RRETURN(S_OK);
  802. }
  803. if ( pObjectInfo->NamespaceName
  804. && !pObjectInfo->TreeName
  805. && !pObjectInfo->NumComponents
  806. )
  807. {
  808. pObjectInfo->ObjectType = TOKEN_NAMESPACE;
  809. }
  810. else if ( pObjectInfo->NamespaceName
  811. && pObjectInfo->TreeName
  812. && pObjectInfo->NumComponents)
  813. {
  814. switch (pObjectInfo->dwPathType) {
  815. case PATHTYPE_WINDOWS:
  816. if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,SCHEMA_NAME))
  817. pObjectInfo->ObjectType = TOKEN_SCHEMA;
  818. else if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,ROOTDSE_NAME))
  819. pObjectInfo->ObjectType = TOKEN_ROOTDSE;
  820. break;
  821. case PATHTYPE_X500:
  822. default:
  823. if (!_tcsicmp(pObjectInfo->ComponentArray[pObjectInfo->NumComponents - 1].szComponent,SCHEMA_NAME))
  824. pObjectInfo->ObjectType = TOKEN_SCHEMA;
  825. else if (!_tcsicmp(pObjectInfo->ComponentArray[pObjectInfo->NumComponents - 1].szComponent,ROOTDSE_NAME))
  826. pObjectInfo->ObjectType = TOKEN_ROOTDSE;
  827. break;
  828. }
  829. }else if ( pObjectInfo->NamespaceName
  830. && !pObjectInfo->TreeName
  831. && pObjectInfo->NumComponents)
  832. {
  833. switch (pObjectInfo->dwPathType) {
  834. case PATHTYPE_WINDOWS:
  835. if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,SCHEMA_NAME))
  836. pObjectInfo->ObjectType = TOKEN_SCHEMA;
  837. else if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,ROOTDSE_NAME))
  838. pObjectInfo->ObjectType = TOKEN_ROOTDSE;
  839. break;
  840. case PATHTYPE_X500:
  841. default:
  842. if (!_tcsicmp(pObjectInfo->ComponentArray[pObjectInfo->NumComponents - 1].szComponent,SCHEMA_NAME))
  843. pObjectInfo->ObjectType = TOKEN_SCHEMA;
  844. else if (!_tcsicmp(pObjectInfo->ComponentArray[pObjectInfo->NumComponents - 1].szComponent,ROOTDSE_NAME))
  845. pObjectInfo->ObjectType = TOKEN_ROOTDSE;
  846. break;
  847. }
  848. }
  849. RRETURN(S_OK);
  850. }
  851. HRESULT
  852. GetServerLessBasedObject(
  853. LPWSTR szBuffer,
  854. POBJECTINFO pObjectInfo,
  855. CCredentials& Credentials,
  856. LPVOID * ppObject
  857. )
  858. {
  859. HRESULT hr = S_OK;
  860. DWORD dwStatus = NO_ERROR;
  861. TCHAR *pszLDAPServer = NULL;
  862. TCHAR *pszLDAPDn = NULL;
  863. TCHAR *pszParent = NULL;
  864. TCHAR *pszCommonName = NULL;
  865. TCHAR szADsClassName[64];
  866. WCHAR szDomainName[MAX_PATH];
  867. WCHAR szServerName[MAX_PATH];
  868. WCHAR *pszServerName=NULL;
  869. IADs *pADs = NULL;
  870. LPTSTR *aValues = NULL;
  871. int nCount = 0;
  872. TCHAR *pszLast = NULL;
  873. BOOL fVerify = FALSE ;
  874. DWORD dwPort = 0;
  875. ADS_LDP *ld = NULL;
  876. BOOL fFastBind = Credentials.GetAuthFlags() & ADS_FAST_BIND;
  877. BOOL fUseSpecifiedServer = (gpszStickyServerName != NULL);
  878. //
  879. // Validate that this ADs pathname is to be processed by
  880. // us - as in the provider name is LDAP:
  881. //
  882. hr = ValidateProvider(pObjectInfo);
  883. BAIL_ON_FAILURE(hr);
  884. hr = ValidateObjectType(pObjectInfo);
  885. BAIL_ON_FAILURE(hr);
  886. switch (pObjectInfo->ObjectType) {
  887. case TOKEN_NAMESPACE:
  888. //
  889. // This means that this is a namespace object;
  890. // instantiate the namespace object
  891. //
  892. hr = GetNamespaceObject(
  893. pObjectInfo,
  894. Credentials,
  895. ppObject
  896. );
  897. BAIL_ON_FAILURE(hr);
  898. break;
  899. case TOKEN_ROOTDSE:
  900. //
  901. // This means taht this is a namespace object;
  902. // instantiate the namespace object
  903. //
  904. hr = GetRootDSEObject(
  905. pObjectInfo,
  906. Credentials,
  907. ppObject
  908. );
  909. BAIL_ON_FAILURE(hr);
  910. break;
  911. case TOKEN_SCHEMA:
  912. case TOKEN_CLASS:
  913. case TOKEN_PROPERTY:
  914. case TOKEN_SYNTAX:
  915. hr = GetSchemaObject(
  916. pObjectInfo,
  917. Credentials,
  918. pObjectInfo->PortNumber,
  919. ppObject
  920. );
  921. BAIL_ON_FAILURE(hr);
  922. break;
  923. default:
  924. if ( pObjectInfo->TreeName == NULL )
  925. {
  926. LPTSTR pszName;
  927. LPTSTR aAddresses[5];
  928. //
  929. // fVerify is initially FALSE. If TRUE DsGetDCName will hit the net.
  930. //
  931. RetryGetDefaultServer:
  932. dwStatus = GetDefaultServer(
  933. pObjectInfo->PortNumber,
  934. fVerify,
  935. szDomainName,
  936. szServerName,
  937. TRUE
  938. );
  939. if (dwStatus) {
  940. hr = HRESULT_FROM_WIN32(dwStatus);
  941. BAIL_ON_FAILURE(hr);
  942. }
  943. pszServerName=szServerName;
  944. if (fUseSpecifiedServer) {
  945. //
  946. // We need to change the name of the domain to be that of
  947. // the server we want to target. The swap is made if
  948. // 1) gpszDomainName == NULL, that implies that just
  949. // a serverName was set and not which domain it applies to.
  950. // 2) If a domainName is specified, then the domainName
  951. // from above should be that set in the global pointer for
  952. // the target server to be changed.
  953. //
  954. if ((gpszStickyDomainName
  955. && (!_wcsicmp(szDomainName, gpszStickyDomainName))
  956. )
  957. || (gpszStickyDomainName == NULL)
  958. ) {
  959. //
  960. // We need to change the target to the server.
  961. //
  962. wcscpy(szDomainName,gpszStickyServerName);
  963. pszServerName = NULL;
  964. //
  965. // Make sure if server is down we go to another
  966. // server on the retryGetDefault server path.
  967. //
  968. fUseSpecifiedServer = FALSE;
  969. }
  970. }
  971. hr = BuildLDAPPathFromADsPath2(
  972. szBuffer,
  973. &pszLDAPServer,
  974. &pszLDAPDn,
  975. &dwPort
  976. );
  977. nCount = 0;
  978. // We need to open object here because we want to
  979. // keep the handle open, read will open/close if there
  980. // are no outstanding connections which is likely the case
  981. hr = LdapOpenObject2(
  982. szDomainName,
  983. pszServerName,
  984. pszLDAPDn,
  985. &ld,
  986. Credentials,
  987. dwPort
  988. );
  989. if (SUCCEEDED(hr) && !fFastBind) {
  990. hr = LdapReadAttributeFast(
  991. ld,
  992. pszLDAPDn,
  993. TEXT("objectClass"),
  994. &aValues,
  995. &nCount
  996. );
  997. BAIL_ON_FAILURE(hr);
  998. }
  999. //
  1000. // If server not present and we have NOT tried with fVerify
  1001. // set to TRUE.
  1002. //
  1003. if (((hr == HRESULT_FROM_WIN32(ERROR_BAD_NETPATH)) ||
  1004. (hr == HRESULT_FROM_WIN32(ERROR_DS_SERVER_DOWN)))
  1005. && !fVerify)
  1006. {
  1007. DWORD Last = LastVerifyDefaultServer ;
  1008. DWORD Current = GetTickCount() ;
  1009. //
  1010. // If tick is zero, assume first time. In the very unlikely
  1011. // event we wrapped managed to get exactly zero, we pay the
  1012. // cost of the DsGetDcName (with verify).
  1013. //
  1014. if ((Last == 0) ||
  1015. ((Last <= Current) && ((Current-Last) > DC_NORETRY)) ||
  1016. ((Last > Current) &&
  1017. ((Current+(((DWORD)(-1))- Last)) > DC_NORETRY))) {
  1018. //
  1019. // Set the time. Note this is not critical section
  1020. // protected and in this case it is not necessary.
  1021. //
  1022. LastVerifyDefaultServer = GetTickCount() ;
  1023. fVerify = TRUE ;
  1024. goto RetryGetDefaultServer ;
  1025. }
  1026. }
  1027. }
  1028. BAIL_ON_FAILURE(hr);
  1029. if ( (nCount == 0) && !fFastBind)
  1030. {
  1031. // This object exists but does not have an objectClass. We
  1032. // can't do anything without the objectClass. Hence, return
  1033. // bad path error.
  1034. hr = E_ADS_BAD_PATHNAME;
  1035. BAIL_ON_FAILURE(hr);
  1036. }
  1037. hr = BuildADsParentPathFromObjectInfo2(
  1038. pObjectInfo,
  1039. &pszParent,
  1040. &pszCommonName
  1041. );
  1042. BAIL_ON_FAILURE(hr);
  1043. if (fFastBind) {
  1044. hr = CLDAPGenObject::CreateGenericObject(
  1045. pszParent,
  1046. pszCommonName,
  1047. L"Top",
  1048. Credentials,
  1049. ADS_OBJECT_BOUND,
  1050. IID_IADs,
  1051. (void **) &pADs,
  1052. fFastBind
  1053. );
  1054. } else {
  1055. hr = CLDAPGenObject::CreateGenericObject(
  1056. pszParent,
  1057. pszCommonName,
  1058. aValues,
  1059. nCount,
  1060. Credentials,
  1061. ADS_OBJECT_BOUND,
  1062. IID_IADs,
  1063. (void **) &pADs,
  1064. fFastBind
  1065. );
  1066. }
  1067. BAIL_ON_FAILURE(hr);
  1068. //
  1069. // InstantiateDerivedObject should add-ref this pointer for us.
  1070. //
  1071. hr = pADs->QueryInterface(
  1072. IID_IUnknown,
  1073. ppObject
  1074. );
  1075. BAIL_ON_FAILURE(hr);
  1076. break;
  1077. }
  1078. error:
  1079. if (pADs)
  1080. pADs->Release();
  1081. if ( aValues )
  1082. LdapValueFree( aValues );
  1083. if ( pszLDAPServer )
  1084. FreeADsStr( pszLDAPServer );
  1085. if (pszLDAPDn) {
  1086. FreeADsStr(pszLDAPDn);
  1087. }
  1088. if ( pszParent )
  1089. FreeADsStr( pszParent );
  1090. if ( pszCommonName )
  1091. FreeADsStr( pszCommonName );
  1092. // If ld is open, we need to close it, note that if the object
  1093. // was created successfuly, the Generic object created will have
  1094. // the outstanding reference, if not the connection will be torn
  1095. // down as should be expected.
  1096. if (ld) {
  1097. LdapCloseObject(ld);
  1098. }
  1099. RRETURN(hr);
  1100. }
  1101. HRESULT
  1102. GetObject(
  1103. LPTSTR szBuffer,
  1104. CCredentials& Credentials,
  1105. LPVOID * ppObject
  1106. )
  1107. {
  1108. HRESULT hr = S_OK;
  1109. OBJECTINFO ObjectInfo;
  1110. POBJECTINFO pObjectInfo = &ObjectInfo;
  1111. if (!szBuffer || !ppObject) {
  1112. hr = E_INVALIDARG;
  1113. RRETURN_EXP_IF_ERR(hr);
  1114. }
  1115. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  1116. pObjectInfo->ObjectType = TOKEN_LDAPOBJECT;
  1117. hr = ADsObject(szBuffer, pObjectInfo);
  1118. BAIL_ON_FAILURE(hr);
  1119. switch (pObjectInfo->dwServerPresent) {
  1120. case TRUE:
  1121. hr = GetServerBasedObject(
  1122. szBuffer,
  1123. pObjectInfo,
  1124. Credentials,
  1125. ppObject
  1126. );
  1127. break;
  1128. case FALSE:
  1129. hr = GetServerLessBasedObject(
  1130. szBuffer,
  1131. pObjectInfo,
  1132. Credentials,
  1133. ppObject
  1134. );
  1135. }
  1136. BAIL_ON_FAILURE(hr);
  1137. error:
  1138. if (pObjectInfo) {
  1139. FreeObjectInfo(pObjectInfo);
  1140. }
  1141. RRETURN_EXP_IF_ERR(hr);
  1142. }