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.

638 lines
20 KiB

  1. //
  2. // Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
  3. //
  4. // ***************************************************************************
  5. //
  6. // Original Author: Rajesh Rao
  7. //
  8. // $Author: rajeshr $
  9. // $Date: 6/11/98 4:43p $
  10. // $Workfile:ldapcach.cpp $
  11. //
  12. // $Modtime: 6/11/98 11:21a $
  13. // $Revision: 1 $
  14. // $Nokeywords: $
  15. //
  16. //
  17. // Description: Cache for LDAP Schema objects.
  18. //
  19. //***************************************************************************
  20. #include "precomp.h"
  21. // Initialize the statics
  22. LPCWSTR CLDAPCache :: ROOT_DSE_PATH = L"LDAP://RootDSE";
  23. LPCWSTR CLDAPCache :: SCHEMA_NAMING_CONTEXT = L"schemaNamingContext";
  24. LPCWSTR CLDAPCache :: LDAP_PREFIX = L"LDAP://";
  25. LPCWSTR CLDAPCache :: LDAP_TOP_PREFIX = L"LDAP://CN=top,";
  26. LPCWSTR CLDAPCache :: RIGHT_BRACKET = L")";
  27. LPCWSTR CLDAPCache :: OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA = L"(objectCategory=attributeSchema)";
  28. DWORD CLDAPCache::dwLDAPCacheCount = 0;
  29. //***************************************************************************
  30. //
  31. // CLDAPCache::CLDAPCache
  32. //
  33. // Purpose : Constructor. Fills in the cache with all the properties in LDAP.
  34. //
  35. // Parameters:
  36. // dsLog : The CDSLog object onto which logging will be done.
  37. //***************************************************************************
  38. CLDAPCache :: CLDAPCache()
  39. {
  40. dwLDAPCacheCount++;
  41. m_isInitialized = FALSE;
  42. m_pDirectorySearchSchemaContainer = NULL;
  43. // Initialize the search preferences often used
  44. m_pSearchInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  45. m_pSearchInfo[0].vValue.dwType = ADSTYPE_INTEGER;
  46. m_pSearchInfo[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
  47. m_pSearchInfo[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
  48. m_pSearchInfo[1].vValue.dwType = ADSTYPE_INTEGER;
  49. m_pSearchInfo[1].vValue.Integer = 64;
  50. /*
  51. m_pSearchInfo[2].dwSearchPref = ADS_SEARCHPREF_CACHE_RESULTS;
  52. m_pSearchInfo[2].vValue.dwType = ADSTYPE_BOOLEAN;
  53. m_pSearchInfo[2].vValue.Boolean = 0;
  54. */
  55. m_lpszSchemaContainerSuffix = NULL;
  56. m_lpszSchemaContainerPath = NULL;
  57. // Get the ADSI path of the schema container and store it for future use
  58. //========================================================================
  59. IADs *pRootDSE = NULL;
  60. HRESULT result;
  61. if(SUCCEEDED(result = ADsOpenObject((LPWSTR)ROOT_DSE_PATH, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IADs, (LPVOID *) &pRootDSE)))
  62. {
  63. // Get the location of the schema container
  64. BSTR strSchemaPropertyName = SysAllocString((LPWSTR) SCHEMA_NAMING_CONTEXT);
  65. // Get the schemaNamingContext property. This property contains the ADSI path
  66. // of the schema container
  67. VARIANT variant;
  68. VariantInit(&variant);
  69. if(SUCCEEDED(result = pRootDSE->Get(strSchemaPropertyName, &variant)))
  70. {
  71. // Store the ADSI path to the schema container
  72. m_lpszSchemaContainerSuffix = NULL;
  73. if(m_lpszSchemaContainerSuffix = new WCHAR[wcslen(variant.bstrVal) + 1])
  74. {
  75. wcscpy(m_lpszSchemaContainerSuffix, variant.bstrVal );
  76. g_pLogObject->WriteW( L"CLDAPCache :: Got Schema Container as : %s\r\n", m_lpszSchemaContainerSuffix);
  77. }
  78. // Form the schema container path
  79. //==================================
  80. m_lpszSchemaContainerPath = NULL;
  81. if(m_lpszSchemaContainerPath = new WCHAR[wcslen(LDAP_PREFIX) + wcslen(m_lpszSchemaContainerSuffix) + 1])
  82. {
  83. wcscpy(m_lpszSchemaContainerPath, LDAP_PREFIX);
  84. wcscat(m_lpszSchemaContainerPath, m_lpszSchemaContainerSuffix);
  85. m_isInitialized = TRUE;
  86. /*
  87. if(SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer)))
  88. {
  89. g_pLogObject->WriteW( L"CLDAPCache :: Got IDirectorySearch on Schema Container \r\n");
  90. if(SUCCEEDED(result = InitializeObjectTree()))
  91. {
  92. m_isInitialized = TRUE;
  93. }
  94. else
  95. g_pLogObject->WriteW( L"CLDAPCache :: InitializeObjectTree() FAILED : %x \r\n", result);
  96. }
  97. else
  98. g_pLogObject->WriteW( L"CLDAPCache :: FAILED to get IDirectorySearch on Schema Container : %x\r\n", result);
  99. */
  100. }
  101. }
  102. else
  103. g_pLogObject->WriteW( L"CLDAPCache :: Get on RootDSE FAILED : %x\r\n", result);
  104. SysFreeString(strSchemaPropertyName);
  105. VariantClear(&variant);
  106. pRootDSE->Release();
  107. }
  108. else
  109. g_pLogObject->WriteW( L"CLDAPClassProvider :: InitializeLDAPProvider ADsOpenObject on RootDSE FAILED : %x\r\n", result);
  110. }
  111. //***************************************************************************
  112. //
  113. // CLDAPCache::~CLDAPCache
  114. //
  115. // Purpose : Destructor
  116. //
  117. //***************************************************************************
  118. CLDAPCache :: ~CLDAPCache()
  119. {
  120. dwLDAPCacheCount--;
  121. if(m_pDirectorySearchSchemaContainer)
  122. m_pDirectorySearchSchemaContainer->Release();
  123. delete [] m_lpszSchemaContainerSuffix;
  124. delete [] m_lpszSchemaContainerPath;
  125. }
  126. //***************************************************************************
  127. //
  128. // CLDAPCache::GetProperty
  129. //
  130. // Purpose : Retreives the IDirectory interface of an LDAP property
  131. //
  132. // Parameters:
  133. // lpszPropertyName : The name of the LDAP Property to be retreived
  134. // ppADSIProperty : The address of the pointer where the CADSIProperty object will be placed
  135. // bWBEMName : True if the lpszPropertyName is the WBEM name. False, if it is the LDAP name
  136. //
  137. // Return value:
  138. // The COM value representing the return status. The user should release the object when done.
  139. //
  140. //***************************************************************************
  141. HRESULT CLDAPCache :: GetProperty(LPCWSTR lpszPropertyName, CADSIProperty **ppADSIProperty, BOOLEAN bWBEMName)
  142. {
  143. HRESULT result = E_FAIL;
  144. // Get the LDAP property name from the WBEM class name
  145. LPWSTR lpszLDAPPropertyName = NULL;
  146. if(bWBEMName)
  147. lpszLDAPPropertyName = CLDAPHelper::UnmangleWBEMNameToLDAP(lpszPropertyName);
  148. else
  149. lpszLDAPPropertyName = (LPWSTR)lpszPropertyName; // Save a copy by casting, be careful when deleting
  150. try
  151. {
  152. // This is a cached implementation
  153. // Check the object tree first
  154. //===================================
  155. if((*ppADSIProperty) = (CADSIProperty *) m_objectTree.GetElement(lpszLDAPPropertyName))
  156. {
  157. // Found it in the tree. Nothing more to be done. It has already been 'addreff'ed
  158. result = S_OK;
  159. }
  160. else // Get it from ADSI
  161. {
  162. if(!m_pDirectorySearchSchemaContainer)
  163. {
  164. if(!SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer)))
  165. result = E_FAIL;
  166. }
  167. else
  168. result = S_OK;
  169. if(SUCCEEDED(result))
  170. {
  171. // Search for the property
  172. LPWSTR lpszQuery = NULL;
  173. if(lpszQuery = new WCHAR[ wcslen(OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA) + wcslen(LDAP_DISPLAY_NAME_ATTR) + wcslen(lpszLDAPPropertyName) + 20])
  174. {
  175. try
  176. {
  177. wcscpy(lpszQuery, LEFT_BRACKET_STR);
  178. wcscat(lpszQuery, AMPERSAND_STR);
  179. wcscat(lpszQuery, OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA);
  180. wcscat(lpszQuery, LEFT_BRACKET_STR);
  181. wcscat(lpszQuery, LDAP_DISPLAY_NAME_ATTR);
  182. wcscat(lpszQuery, EQUALS_STR);
  183. wcscat(lpszQuery, lpszLDAPPropertyName);
  184. wcscat(lpszQuery, RIGHT_BRACKET_STR);
  185. wcscat(lpszQuery, RIGHT_BRACKET_STR);
  186. ADS_SEARCH_HANDLE hADSSearchOuter;
  187. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->ExecuteSearch(lpszQuery, NULL, -1, &hADSSearchOuter)))
  188. {
  189. try
  190. {
  191. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetNextRow(hADSSearchOuter)) &&
  192. result != S_ADS_NOMORE_ROWS)
  193. {
  194. *ppADSIProperty = NULL;
  195. if(*ppADSIProperty = new CADSIProperty())
  196. {
  197. try
  198. {
  199. // Fill in the details of the property
  200. if(SUCCEEDED(result = FillInAProperty(*ppADSIProperty, hADSSearchOuter)))
  201. {
  202. // Add the property to the tree
  203. m_objectTree.AddElement((*ppADSIProperty)->GetADSIPropertyName(), *ppADSIProperty);
  204. // No need to release it since we're returning it
  205. }
  206. else
  207. {
  208. delete *ppADSIProperty;
  209. *ppADSIProperty = NULL;
  210. }
  211. }
  212. catch ( ... )
  213. {
  214. delete *ppADSIProperty;
  215. *ppADSIProperty = NULL;
  216. throw;
  217. }
  218. }
  219. else
  220. result = E_OUTOFMEMORY;
  221. }
  222. }
  223. catch ( ... )
  224. {
  225. m_pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter);
  226. throw;
  227. }
  228. m_pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter);
  229. }
  230. }
  231. catch ( ... )
  232. {
  233. delete [] lpszQuery;
  234. throw;
  235. }
  236. delete [] lpszQuery;
  237. }
  238. else
  239. result = E_OUTOFMEMORY;
  240. }
  241. }
  242. }
  243. catch ( ... )
  244. {
  245. if(bWBEMName)
  246. {
  247. delete[] lpszLDAPPropertyName;
  248. lpszLDAPPropertyName = NULL;
  249. }
  250. throw;
  251. }
  252. // Delete only what was allocated in this function
  253. //================================================
  254. if(bWBEMName)
  255. {
  256. delete[] lpszLDAPPropertyName;
  257. lpszLDAPPropertyName = NULL;
  258. }
  259. return result;
  260. }
  261. //***************************************************************************
  262. //
  263. // CLDAPCache::GetClass
  264. //
  265. // Purpose : See Header File
  266. //
  267. //***************************************************************************
  268. HRESULT CLDAPCache :: GetClass(LPCWSTR lpszWBEMClassName, LPCWSTR lpszLDAPClassName, CADSIClass **ppADSIClass)
  269. {
  270. /************************************************************
  271. *************************************************************
  272. ***** NO Cache implementation for now. Always fetch everytime
  273. *************************************************************
  274. *************************************************************/
  275. *ppADSIClass = NULL;
  276. if(!(*ppADSIClass = new CADSIClass(lpszWBEMClassName, lpszLDAPClassName)) )
  277. return E_OUTOFMEMORY;
  278. HRESULT result = E_FAIL;
  279. try
  280. {
  281. if(!m_pDirectorySearchSchemaContainer)
  282. {
  283. if(!SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer)))
  284. result = E_FAIL;
  285. }
  286. else
  287. result = S_OK;
  288. if(SUCCEEDED(result))
  289. {
  290. result = CLDAPHelper::GetLDAPClassFromLDAPName(m_pDirectorySearchSchemaContainer,
  291. m_lpszSchemaContainerSuffix,
  292. m_pSearchInfo,
  293. 2,
  294. *ppADSIClass
  295. );
  296. }
  297. }
  298. catch ( ... )
  299. {
  300. // at least GetLDAPClassFromLDAPName throws
  301. delete *ppADSIClass;
  302. *ppADSIClass = NULL;
  303. throw;
  304. }
  305. if(!SUCCEEDED(result))
  306. {
  307. delete *ppADSIClass;
  308. *ppADSIClass = NULL;
  309. }
  310. return result;
  311. }
  312. //***************************************************************************
  313. //
  314. // CLDAPCache::GetSchemaContainerSearch
  315. //
  316. // Purpose : To return the IDirectorySearch interface on the schema container
  317. //
  318. // Parameters:
  319. // ppDirectorySearch : The address where the pointer to the required interface will
  320. // be stored.
  321. //
  322. //
  323. // Return Value: The COM result representing the status. The user should release
  324. // the interface pointer when done with it.
  325. //***************************************************************************
  326. HRESULT CLDAPCache :: GetSchemaContainerSearch(IDirectorySearch ** ppDirectorySearch)
  327. {
  328. if(m_pDirectorySearchSchemaContainer)
  329. {
  330. *ppDirectorySearch = m_pDirectorySearchSchemaContainer;
  331. (*ppDirectorySearch)->AddRef();
  332. return S_OK;
  333. }
  334. else
  335. return E_FAIL;
  336. }
  337. //***************************************************************************
  338. //
  339. // CLDAPCache::EnumerateClasses
  340. //
  341. // Purpose : See Header
  342. //
  343. //***************************************************************************
  344. HRESULT CLDAPCache::EnumerateClasses(LPCWSTR lpszWBEMSuperclass,
  345. BOOLEAN bDeep,
  346. LPWSTR **pppADSIClasses,
  347. DWORD *pdwNumRows,
  348. BOOLEAN bArtificialClass)
  349. {
  350. // Get the LDAP name of the super class
  351. // Do not mangle if it one of the classes that we know
  352. //=====================================================
  353. LPWSTR lpszLDAPSuperClassName = NULL;
  354. if(_wcsicmp(lpszWBEMSuperclass, LDAP_BASE_CLASS) != 0)
  355. {
  356. lpszLDAPSuperClassName = CLDAPHelper::UnmangleWBEMNameToLDAP(lpszWBEMSuperclass);
  357. if(!lpszLDAPSuperClassName) // We were returned a NULL by the Unmangler, so not a DS class
  358. {
  359. *pppADSIClasses = NULL;
  360. *pdwNumRows = 0;
  361. return S_OK;
  362. }
  363. }
  364. HRESULT result = E_FAIL;
  365. if(!m_pDirectorySearchSchemaContainer)
  366. {
  367. if(!SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer)))
  368. result = E_FAIL;
  369. }
  370. else
  371. result = S_OK;
  372. if(SUCCEEDED(result))
  373. {
  374. result = CLDAPHelper::EnumerateClasses(m_pDirectorySearchSchemaContainer,
  375. m_lpszSchemaContainerSuffix,
  376. m_pSearchInfo,
  377. 2,
  378. lpszLDAPSuperClassName,
  379. bDeep,
  380. pppADSIClasses,
  381. pdwNumRows,
  382. bArtificialClass);
  383. }
  384. // If the superclass is an artificial class like "ADS_User", then a concrete sub-class "DS_User" exists.
  385. // This is added manually here, to both the EnumInfoList as well as the structure being returned
  386. // The above call to EnumerateClasses would have helpfully left an extra element unfilled at the beginning
  387. // of the array
  388. if(SUCCEEDED(result) && bArtificialClass)
  389. {
  390. (*pppADSIClasses)[0] = NULL;
  391. if((*pppADSIClasses)[0] = new WCHAR[wcslen(lpszWBEMSuperclass+1) + 1])
  392. wcscpy((*pppADSIClasses)[0], lpszWBEMSuperclass+1);
  393. else
  394. result = E_OUTOFMEMORY;
  395. }
  396. delete[] lpszLDAPSuperClassName;
  397. return result;
  398. }
  399. //***************************************************************************
  400. //
  401. // CLDAPCache::IsInitialized
  402. //
  403. // Purpose : Indicates whether the cache was created and initialized succeddfully
  404. //
  405. // Parameters:
  406. // None
  407. //
  408. // Return value:
  409. // A boolean value indicating the status
  410. //
  411. //***************************************************************************
  412. BOOLEAN CLDAPCache :: IsInitialized()
  413. {
  414. return m_isInitialized;
  415. }
  416. //***************************************************************************
  417. //
  418. // CLDAPCache :: InitializeObjectTree
  419. //
  420. // Purpose : Initialize the lexically ordered binary tree with all the properties
  421. // LDAP
  422. //
  423. // Parameters:
  424. // None
  425. //
  426. // Return Value: The COM status representing the return value
  427. //***************************************************************************
  428. HRESULT CLDAPCache :: InitializeObjectTree()
  429. {
  430. // Get the attributes of all the instances of the
  431. // class "AttributeSchema"
  432. //=================================================
  433. HRESULT result = E_FAIL;
  434. /*
  435. // Now perform a search for all the attributes
  436. //============================================
  437. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->SetSearchPreference(m_pSearchInfo, 2)))
  438. {
  439. ADS_SEARCH_HANDLE hADSSearchOuter;
  440. // Count of attributes
  441. DWORD dwCount = 0;
  442. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->ExecuteSearch((LPWSTR)OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA, NULL, -1, &hADSSearchOuter)))
  443. {
  444. CADSIProperty *pNextProperty;
  445. while(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetNextRow(hADSSearchOuter)) &&
  446. result != S_ADS_NOMORE_ROWS)
  447. {
  448. pNextProperty = new CADSIProperty();
  449. dwCount ++;
  450. // Fill in the details of the property
  451. FillInAProperty(pNextProperty, hADSSearchOuter);
  452. // Add the property to the tree
  453. m_objectTree.AddElement(pNextProperty->GetADSIPropertyName(), pNextProperty);
  454. pNextProperty->Release();
  455. }
  456. m_pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter);
  457. }
  458. g_pLogObject->WriteW( L"CLDAPCache :: InitializeObjectTree() Initialized with %d attributes\r\n", dwCount);
  459. }
  460. else
  461. g_pLogObject->WriteW( L"CLDAPCache :: InitializeObjectTree() SetSearchPreference() FAILED with %x\r\n", result);
  462. */
  463. return result;
  464. }
  465. HRESULT CLDAPCache :: FillInAProperty(CADSIProperty *pNextProperty, ADS_SEARCH_HANDLE hADSSearchOuter)
  466. {
  467. ADS_SEARCH_COLUMN adsNextColumn;
  468. HRESULT result = E_FAIL;
  469. LPWSTR lpszWBEMName = NULL;
  470. BOOLEAN bNeedToCheckForORName = FALSE;
  471. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)ATTRIBUTE_SYNTAX_ATTR, &adsNextColumn )))
  472. {
  473. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  474. result = E_FAIL;
  475. else
  476. {
  477. pNextProperty->SetSyntaxOID(adsNextColumn.pADsValues->CaseIgnoreString);
  478. if(_wcsicmp(adsNextColumn.pADsValues->CaseIgnoreString, DN_WITH_BINARY_OID) == 0)
  479. bNeedToCheckForORName = TRUE;
  480. }
  481. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  482. }
  483. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)IS_SINGLE_VALUED_ATTR, &adsNextColumn )))
  484. {
  485. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  486. result = E_FAIL;
  487. else
  488. pNextProperty->SetMultiValued( (adsNextColumn.pADsValues->Boolean)? FALSE : TRUE);
  489. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  490. }
  491. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)ATTRIBUTE_ID_ATTR, &adsNextColumn )))
  492. {
  493. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  494. result = E_FAIL;
  495. else
  496. pNextProperty->SetAttributeID(adsNextColumn.pADsValues->CaseIgnoreString);
  497. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  498. }
  499. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)COMMON_NAME_ATTR, &adsNextColumn )))
  500. {
  501. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  502. result = E_FAIL;
  503. else
  504. pNextProperty->SetCommonName(adsNextColumn.pADsValues->CaseIgnoreString);
  505. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  506. }
  507. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)LDAP_DISPLAY_NAME_ATTR, &adsNextColumn )))
  508. {
  509. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  510. result = E_FAIL;
  511. else
  512. {
  513. pNextProperty->SetADSIPropertyName(adsNextColumn.pADsValues->CaseIgnoreString);
  514. lpszWBEMName = CLDAPHelper::MangleLDAPNameToWBEM(adsNextColumn.pADsValues->CaseIgnoreString);
  515. pNextProperty->SetWBEMPropertyName(lpszWBEMName);
  516. delete []lpszWBEMName;
  517. }
  518. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  519. }
  520. if(SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)MAPI_ID_ATTR, &adsNextColumn )))
  521. {
  522. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  523. result = E_FAIL;
  524. else
  525. pNextProperty->SetMAPI_ID(adsNextColumn.pADsValues->Integer);
  526. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  527. }
  528. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)OM_SYNTAX_ATTR, &adsNextColumn )))
  529. {
  530. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  531. result = E_FAIL;
  532. else
  533. pNextProperty->SetOMSyntax(adsNextColumn.pADsValues->Integer);
  534. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  535. }
  536. if(bNeedToCheckForORName && SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)OM_OBJECT_CLASS_ATTR, &adsNextColumn )))
  537. {
  538. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  539. result = E_FAIL;
  540. else
  541. {
  542. // Just the first octet in the LPBYTE array is enough for differntiating between ORName and DNWithBinary
  543. if((adsNextColumn.pADsValues->OctetString).lpValue[0] == 0x56)
  544. pNextProperty->SetORName(TRUE);
  545. }
  546. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  547. }
  548. if(SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)SEARCH_FLAGS_ATTR, &adsNextColumn )))
  549. {
  550. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  551. result = E_FAIL;
  552. else
  553. pNextProperty->SetSearchFlags(adsNextColumn.pADsValues->Integer);
  554. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  555. }
  556. if(SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)SYSTEM_ONLY_ATTR, &adsNextColumn )))
  557. {
  558. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  559. result = E_FAIL;
  560. else
  561. pNextProperty->SetSystemOnly(TRUE);
  562. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  563. }
  564. return result;
  565. }