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.

645 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. if (m_lpszSchemaContainerSuffix)
  124. {
  125. delete [] m_lpszSchemaContainerSuffix;
  126. }
  127. if (m_lpszSchemaContainerPath)
  128. {
  129. delete [] m_lpszSchemaContainerPath;
  130. }
  131. }
  132. //***************************************************************************
  133. //
  134. // CLDAPCache::GetProperty
  135. //
  136. // Purpose : Retreives the IDirectory interface of an LDAP property
  137. //
  138. // Parameters:
  139. // lpszPropertyName : The name of the LDAP Property to be retreived
  140. // ppADSIProperty : The address of the pointer where the CADSIProperty object will be placed
  141. // bWBEMName : True if the lpszPropertyName is the WBEM name. False, if it is the LDAP name
  142. //
  143. // Return value:
  144. // The COM value representing the return status. The user should release the object when done.
  145. //
  146. //***************************************************************************
  147. HRESULT CLDAPCache :: GetProperty(LPCWSTR lpszPropertyName, CADSIProperty **ppADSIProperty, BOOLEAN bWBEMName)
  148. {
  149. HRESULT result = E_FAIL;
  150. // Get the LDAP property name from the WBEM class name
  151. LPWSTR lpszLDAPPropertyName = NULL;
  152. if(bWBEMName)
  153. lpszLDAPPropertyName = CLDAPHelper::UnmangleWBEMNameToLDAP(lpszPropertyName);
  154. else
  155. lpszLDAPPropertyName = (LPWSTR)lpszPropertyName; // Save a copy by casting, be careful when deleting
  156. try
  157. {
  158. // This is a cached implementation
  159. // Check the object tree first
  160. //===================================
  161. if((*ppADSIProperty) = (CADSIProperty *) m_objectTree.GetElement(lpszLDAPPropertyName))
  162. {
  163. // Found it in the tree. Nothing more to be done. It has already been 'addreff'ed
  164. result = S_OK;
  165. }
  166. else // Get it from ADSI
  167. {
  168. if(!m_pDirectorySearchSchemaContainer)
  169. {
  170. if(!SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer)))
  171. result = E_FAIL;
  172. }
  173. else
  174. result = S_OK;
  175. if(SUCCEEDED(result))
  176. {
  177. // Search for the property
  178. LPWSTR lpszQuery = NULL;
  179. if(lpszQuery = new WCHAR[ wcslen(OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA) + wcslen(LDAP_DISPLAY_NAME_ATTR) + wcslen(lpszLDAPPropertyName) + 20])
  180. {
  181. try
  182. {
  183. wcscpy(lpszQuery, LEFT_BRACKET_STR);
  184. wcscat(lpszQuery, AMPERSAND_STR);
  185. wcscat(lpszQuery, OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA);
  186. wcscat(lpszQuery, LEFT_BRACKET_STR);
  187. wcscat(lpszQuery, LDAP_DISPLAY_NAME_ATTR);
  188. wcscat(lpszQuery, EQUALS_STR);
  189. wcscat(lpszQuery, lpszLDAPPropertyName);
  190. wcscat(lpszQuery, RIGHT_BRACKET_STR);
  191. wcscat(lpszQuery, RIGHT_BRACKET_STR);
  192. ADS_SEARCH_HANDLE hADSSearchOuter;
  193. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->ExecuteSearch(lpszQuery, NULL, -1, &hADSSearchOuter)))
  194. {
  195. try
  196. {
  197. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetNextRow(hADSSearchOuter)) &&
  198. result != S_ADS_NOMORE_ROWS)
  199. {
  200. *ppADSIProperty = NULL;
  201. if(*ppADSIProperty = new CADSIProperty())
  202. {
  203. try
  204. {
  205. // Fill in the details of the property
  206. if(SUCCEEDED(result = FillInAProperty(*ppADSIProperty, hADSSearchOuter)))
  207. {
  208. // Add the property to the tree
  209. m_objectTree.AddElement((*ppADSIProperty)->GetADSIPropertyName(), *ppADSIProperty);
  210. // No need to release it since we're returning it
  211. }
  212. else
  213. {
  214. delete *ppADSIProperty;
  215. *ppADSIProperty = NULL;
  216. }
  217. }
  218. catch ( ... )
  219. {
  220. delete *ppADSIProperty;
  221. *ppADSIProperty = NULL;
  222. throw;
  223. }
  224. }
  225. else
  226. result = E_OUTOFMEMORY;
  227. }
  228. }
  229. catch ( ... )
  230. {
  231. m_pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter);
  232. throw;
  233. }
  234. m_pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter);
  235. }
  236. }
  237. catch ( ... )
  238. {
  239. delete [] lpszQuery;
  240. throw;
  241. }
  242. delete [] lpszQuery;
  243. }
  244. else
  245. result = E_OUTOFMEMORY;
  246. }
  247. }
  248. }
  249. catch ( ... )
  250. {
  251. if(bWBEMName)
  252. {
  253. delete[] lpszLDAPPropertyName;
  254. lpszLDAPPropertyName = NULL;
  255. }
  256. throw;
  257. }
  258. // Delete only what was allocated in this function
  259. //================================================
  260. if(bWBEMName)
  261. {
  262. delete[] lpszLDAPPropertyName;
  263. lpszLDAPPropertyName = NULL;
  264. }
  265. return result;
  266. }
  267. //***************************************************************************
  268. //
  269. // CLDAPCache::GetClass
  270. //
  271. // Purpose : See Header File
  272. //
  273. //***************************************************************************
  274. HRESULT CLDAPCache :: GetClass(LPCWSTR lpszWBEMClassName, LPCWSTR lpszLDAPClassName, CADSIClass **ppADSIClass)
  275. {
  276. /************************************************************
  277. *************************************************************
  278. ***** NO Cache implementation for now. Always fetch everytime
  279. *************************************************************
  280. *************************************************************/
  281. *ppADSIClass = NULL;
  282. if(!(*ppADSIClass = new CADSIClass(lpszWBEMClassName, lpszLDAPClassName)) )
  283. return E_OUTOFMEMORY;
  284. HRESULT result = E_FAIL;
  285. try
  286. {
  287. if(!m_pDirectorySearchSchemaContainer)
  288. {
  289. if(!SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer)))
  290. result = E_FAIL;
  291. }
  292. else
  293. result = S_OK;
  294. if(SUCCEEDED(result))
  295. {
  296. result = CLDAPHelper::GetLDAPClassFromLDAPName(m_pDirectorySearchSchemaContainer,
  297. m_lpszSchemaContainerSuffix,
  298. m_pSearchInfo,
  299. 2,
  300. *ppADSIClass
  301. );
  302. }
  303. }
  304. catch ( ... )
  305. {
  306. // at least GetLDAPClassFromLDAPName throws
  307. delete *ppADSIClass;
  308. *ppADSIClass = NULL;
  309. throw;
  310. }
  311. if(!SUCCEEDED(result))
  312. {
  313. delete *ppADSIClass;
  314. *ppADSIClass = NULL;
  315. }
  316. return result;
  317. }
  318. //***************************************************************************
  319. //
  320. // CLDAPCache::GetSchemaContainerSearch
  321. //
  322. // Purpose : To return the IDirectorySearch interface on the schema container
  323. //
  324. // Parameters:
  325. // ppDirectorySearch : The address where the pointer to the required interface will
  326. // be stored.
  327. //
  328. //
  329. // Return Value: The COM result representing the status. The user should release
  330. // the interface pointer when done with it.
  331. //***************************************************************************
  332. HRESULT CLDAPCache :: GetSchemaContainerSearch(IDirectorySearch ** ppDirectorySearch)
  333. {
  334. if(m_pDirectorySearchSchemaContainer)
  335. {
  336. *ppDirectorySearch = m_pDirectorySearchSchemaContainer;
  337. (*ppDirectorySearch)->AddRef();
  338. return S_OK;
  339. }
  340. else
  341. return E_FAIL;
  342. }
  343. //***************************************************************************
  344. //
  345. // CLDAPCache::EnumerateClasses
  346. //
  347. // Purpose : See Header
  348. //
  349. //***************************************************************************
  350. HRESULT CLDAPCache::EnumerateClasses(LPCWSTR lpszWBEMSuperclass,
  351. BOOLEAN bDeep,
  352. LPWSTR **pppADSIClasses,
  353. DWORD *pdwNumRows,
  354. BOOLEAN bArtificialClass)
  355. {
  356. // Get the LDAP name of the super class
  357. // Do not mangle if it one of the classes that we know
  358. //=====================================================
  359. LPWSTR lpszLDAPSuperClassName = NULL;
  360. if(_wcsicmp(lpszWBEMSuperclass, LDAP_BASE_CLASS) != 0)
  361. {
  362. lpszLDAPSuperClassName = CLDAPHelper::UnmangleWBEMNameToLDAP(lpszWBEMSuperclass);
  363. if(!lpszLDAPSuperClassName) // We were returned a NULL by the Unmangler, so not a DS class
  364. {
  365. *pppADSIClasses = NULL;
  366. *pdwNumRows = 0;
  367. return S_OK;
  368. }
  369. }
  370. HRESULT result = E_FAIL;
  371. if(!m_pDirectorySearchSchemaContainer)
  372. {
  373. if(!SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer)))
  374. result = E_FAIL;
  375. }
  376. else
  377. result = S_OK;
  378. if(SUCCEEDED(result))
  379. {
  380. result = CLDAPHelper::EnumerateClasses(m_pDirectorySearchSchemaContainer,
  381. m_lpszSchemaContainerSuffix,
  382. m_pSearchInfo,
  383. 2,
  384. lpszLDAPSuperClassName,
  385. bDeep,
  386. pppADSIClasses,
  387. pdwNumRows,
  388. bArtificialClass);
  389. }
  390. // If the superclass is an artificial class like "ADS_User", then a concrete sub-class "DS_User" exists.
  391. // This is added manually here, to both the EnumInfoList as well as the structure being returned
  392. // The above call to EnumerateClasses would have helpfully left an extra element unfilled at the beginning
  393. // of the array
  394. if(SUCCEEDED(result) && bArtificialClass)
  395. {
  396. (*pppADSIClasses)[0] = NULL;
  397. if((*pppADSIClasses)[0] = new WCHAR[wcslen(lpszWBEMSuperclass+1) + 1])
  398. wcscpy((*pppADSIClasses)[0], lpszWBEMSuperclass+1);
  399. else
  400. result = E_OUTOFMEMORY;
  401. }
  402. delete[] lpszLDAPSuperClassName;
  403. return result;
  404. }
  405. //***************************************************************************
  406. //
  407. // CLDAPCache::IsInitialized
  408. //
  409. // Purpose : Indicates whether the cache was created and initialized succeddfully
  410. //
  411. // Parameters:
  412. // None
  413. //
  414. // Return value:
  415. // A boolean value indicating the status
  416. //
  417. //***************************************************************************
  418. BOOLEAN CLDAPCache :: IsInitialized()
  419. {
  420. return m_isInitialized;
  421. }
  422. //***************************************************************************
  423. //
  424. // CLDAPCache :: InitializeObjectTree
  425. //
  426. // Purpose : Initialize the lexically ordered binary tree with all the properties
  427. // LDAP
  428. //
  429. // Parameters:
  430. // None
  431. //
  432. // Return Value: The COM status representing the return value
  433. //***************************************************************************
  434. HRESULT CLDAPCache :: InitializeObjectTree()
  435. {
  436. // Get the attributes of all the instances of the
  437. // class "AttributeSchema"
  438. //=================================================
  439. HRESULT result = E_FAIL;
  440. /*
  441. // Now perform a search for all the attributes
  442. //============================================
  443. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->SetSearchPreference(m_pSearchInfo, 2)))
  444. {
  445. ADS_SEARCH_HANDLE hADSSearchOuter;
  446. // Count of attributes
  447. DWORD dwCount = 0;
  448. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->ExecuteSearch((LPWSTR)OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA, NULL, -1, &hADSSearchOuter)))
  449. {
  450. CADSIProperty *pNextProperty;
  451. while(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetNextRow(hADSSearchOuter)) &&
  452. result != S_ADS_NOMORE_ROWS)
  453. {
  454. pNextProperty = new CADSIProperty();
  455. dwCount ++;
  456. // Fill in the details of the property
  457. FillInAProperty(pNextProperty, hADSSearchOuter);
  458. // Add the property to the tree
  459. m_objectTree.AddElement(pNextProperty->GetADSIPropertyName(), pNextProperty);
  460. pNextProperty->Release();
  461. }
  462. m_pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter);
  463. }
  464. g_pLogObject->WriteW( L"CLDAPCache :: InitializeObjectTree() Initialized with %d attributes\r\n", dwCount);
  465. }
  466. else
  467. g_pLogObject->WriteW( L"CLDAPCache :: InitializeObjectTree() SetSearchPreference() FAILED with %x\r\n", result);
  468. */
  469. return result;
  470. }
  471. HRESULT CLDAPCache :: FillInAProperty(CADSIProperty *pNextProperty, ADS_SEARCH_HANDLE hADSSearchOuter)
  472. {
  473. ADS_SEARCH_COLUMN adsNextColumn;
  474. HRESULT result = E_FAIL;
  475. LPWSTR lpszWBEMName = NULL;
  476. BOOLEAN bNeedToCheckForORName = FALSE;
  477. if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)ATTRIBUTE_SYNTAX_ATTR, &adsNextColumn )))
  478. {
  479. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  480. result = E_FAIL;
  481. else
  482. {
  483. pNextProperty->SetSyntaxOID(adsNextColumn.pADsValues->CaseIgnoreString);
  484. if(_wcsicmp(adsNextColumn.pADsValues->CaseIgnoreString, DN_WITH_BINARY_OID) == 0)
  485. bNeedToCheckForORName = TRUE;
  486. }
  487. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  488. }
  489. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)IS_SINGLE_VALUED_ATTR, &adsNextColumn )))
  490. {
  491. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  492. result = E_FAIL;
  493. else
  494. pNextProperty->SetMultiValued( (adsNextColumn.pADsValues->Boolean)? FALSE : TRUE);
  495. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  496. }
  497. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)ATTRIBUTE_ID_ATTR, &adsNextColumn )))
  498. {
  499. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  500. result = E_FAIL;
  501. else
  502. pNextProperty->SetAttributeID(adsNextColumn.pADsValues->CaseIgnoreString);
  503. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  504. }
  505. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)COMMON_NAME_ATTR, &adsNextColumn )))
  506. {
  507. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  508. result = E_FAIL;
  509. else
  510. pNextProperty->SetCommonName(adsNextColumn.pADsValues->CaseIgnoreString);
  511. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  512. }
  513. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)LDAP_DISPLAY_NAME_ATTR, &adsNextColumn )))
  514. {
  515. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  516. result = E_FAIL;
  517. else
  518. {
  519. pNextProperty->SetADSIPropertyName(adsNextColumn.pADsValues->CaseIgnoreString);
  520. lpszWBEMName = CLDAPHelper::MangleLDAPNameToWBEM(adsNextColumn.pADsValues->CaseIgnoreString);
  521. pNextProperty->SetWBEMPropertyName(lpszWBEMName);
  522. delete []lpszWBEMName;
  523. }
  524. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  525. }
  526. if(SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)MAPI_ID_ATTR, &adsNextColumn )))
  527. {
  528. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  529. result = E_FAIL;
  530. else
  531. pNextProperty->SetMAPI_ID(adsNextColumn.pADsValues->Integer);
  532. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  533. }
  534. if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)OM_SYNTAX_ATTR, &adsNextColumn )))
  535. {
  536. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  537. result = E_FAIL;
  538. else
  539. pNextProperty->SetOMSyntax(adsNextColumn.pADsValues->Integer);
  540. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  541. }
  542. if(bNeedToCheckForORName && SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)OM_OBJECT_CLASS_ATTR, &adsNextColumn )))
  543. {
  544. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  545. result = E_FAIL;
  546. else
  547. {
  548. // Just the first octet in the LPBYTE array is enough for differntiating between ORName and DNWithBinary
  549. if((adsNextColumn.pADsValues->OctetString).lpValue[0] == 0x56)
  550. pNextProperty->SetORName(TRUE);
  551. }
  552. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  553. }
  554. if(SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)SEARCH_FLAGS_ATTR, &adsNextColumn )))
  555. {
  556. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  557. result = E_FAIL;
  558. else
  559. pNextProperty->SetSearchFlags(adsNextColumn.pADsValues->Integer);
  560. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  561. }
  562. if(SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)SYSTEM_ONLY_ATTR, &adsNextColumn )))
  563. {
  564. if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
  565. result = E_FAIL;
  566. else
  567. pNextProperty->SetSystemOnly(TRUE);
  568. m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn );
  569. }
  570. return result;
  571. }