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.

7428 lines
173 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996
  5. //
  6. // File: cschema.cxx
  7. //
  8. // Contents: LDAP
  9. //
  10. //
  11. // History: 09-01-96 yihsins Created.
  12. //
  13. //----------------------------------------------------------------------------
  14. #include "ldap.hxx"
  15. #pragma hdrstop
  16. #define NT_SCHEMA_CLASS_NAME TEXT("classSchema")
  17. #define NT_SCHEMA_PROPERTY_NAME TEXT("attributeSchema")
  18. #define BEGIN_FILTER TEXT("(& (lDAPDisplayName=")
  19. #define END_FILTER TEXT(") (! (isdefunct=TRUE)))")
  20. struct _syntaxmapping
  21. {
  22. LPTSTR pszSyntax;
  23. LPTSTR pszOID;
  24. DWORD dwOMSyntax;
  25. } aSyntaxMap[] =
  26. {
  27. { TEXT("Boolean"), TEXT("2.5.5.8"), 1 },
  28. { TEXT("Integer"), TEXT("2.5.5.9"), 2 },
  29. { TEXT("OctetString"), TEXT("2.5.5.10"), 4 },
  30. // The following are in ADS only
  31. { TEXT("Counter"), TEXT("2.5.5.9"), 2 },
  32. { TEXT("ADsPath"), TEXT("2.5.5.12"), 64 },
  33. { TEXT("EmailAddress"), TEXT("2.5.5.12"), 64 },
  34. { TEXT("FaxNumber"), TEXT("2.5.5.12"), 64 },
  35. { TEXT("Interval"), TEXT("2.5.5.9"), 2 },
  36. { TEXT("List"), TEXT("2.5.5.10"), 4 },
  37. { TEXT("NetAddress"), TEXT("2.5.5.12"), 64 },
  38. { TEXT("Path"), TEXT("2.5.5.12"), 64 },
  39. { TEXT("PhoneNumber"), TEXT("2.5.5.12"), 64 },
  40. { TEXT("PostalAddress"), TEXT("2.5.5.12"), 64 },
  41. { TEXT("SmallInterval"), TEXT("2.5.5.9"), 2 },
  42. { TEXT("String"), TEXT("2.5.5.12"), 64 },
  43. { TEXT("Time"), TEXT("2.5.5.11"), 23 },
  44. // The following are in NTDS only
  45. { TEXT("INTEGER8"), TEXT("2.5.5.16"), 65 },
  46. { TEXT("UTCTime"), TEXT("2.5.5.11"), 23 },
  47. { TEXT("DN"), TEXT("2.5.5.1"), 127 },
  48. { TEXT("OID"), TEXT("2.5.5.2"), 6 },
  49. { TEXT("DirectoryString"), TEXT("2.5.5.12"), 64 },
  50. { TEXT("PrintableString"), TEXT("2.5.5.5"), 19 },
  51. { TEXT("CaseIgnoreString"), TEXT("2.5.5.4"), 20 },
  52. { TEXT("NumericString"), TEXT("2.5.5.6"), 18 },
  53. { TEXT("IA5String"), TEXT("2.5.5.5"), 22 },
  54. { TEXT("PresentationAddresses"), TEXT("2.5.5.13"), 127 },
  55. { TEXT("ORName"), TEXT("2.5.5.7"), 127 },
  56. { TEXT("DNWithBinary"), TEXT("2.5.5.7"), 127},
  57. // needs additional information to distinguish from ORName
  58. { TEXT("AccessPointDN"), TEXT("2.5.5.14"), 127 },
  59. { TEXT("DNWithString"), TEXT("2.5.5.14"), 127 },
  60. // needs additional information to distinguish from AccessPointDN
  61. { TEXT("NTSecurityDescriptor"), TEXT("2.5.5.15"), 66},
  62. { TEXT("GeneralizedTime"), TEXT("2.5.5.11"), 24},
  63. { TEXT("Enumeration"), TEXT("2.5.5.9"), 10 },
  64. { TEXT("ReplicaLink"), TEXT("2.5.5.10"), 127 },
  65. { TEXT("Sid"), TEXT("2.5.5.17"), 4 },
  66. { TEXT("CaseExactString"), TEXT("2.5.5.3"), 27 }
  67. };
  68. struct _classmapping
  69. {
  70. LPTSTR pszLdapClassName;
  71. LPTSTR pszADsClassName;
  72. const GUID *pCLSID;
  73. const GUID *pPrimaryInterfaceGUID;
  74. } aClassMap[] =
  75. {
  76. { TEXT("user"), USER_CLASS_NAME,
  77. &CLSID_LDAPUser, &IID_IADsUser }, // NTDS
  78. { TEXT("group"), GROUP_CLASS_NAME,
  79. &CLSID_LDAPGroup, &IID_IADsGroup }, // NTDS
  80. { TEXT("localGroup"), GROUP_CLASS_NAME,
  81. &CLSID_LDAPGroup, &IID_IADsGroup }, // NTDS
  82. // { TEXT("computer"), COMPUTER_CLASS_NAME,
  83. // &CLSID_LDAPComputer, &IID_IADsComputer }, // NTDS
  84. { TEXT("printQueue"), PRINTER_CLASS_NAME,
  85. &CLSID_LDAPPrintQueue, &IID_IADsPrintQueue }, // NTDS
  86. { TEXT("country"), TEXT("Country"),
  87. &CLSID_LDAPCountry, &IID_IADs },
  88. { TEXT("locality"), TEXT("Locality"),
  89. &CLSID_LDAPLocality, &IID_IADsLocality },
  90. { TEXT("organization"), TEXT("Organization"),
  91. &CLSID_LDAPO, &IID_IADsO },
  92. { TEXT("organizationalUnit"), TEXT("Organizational Unit"),
  93. &CLSID_LDAPOU, &IID_IADsOU },
  94. { TEXT("domain"), DOMAIN_CLASS_NAME,
  95. &CLSID_LDAPDomain, &IID_IADsDomain },
  96. { TEXT("person"), USER_CLASS_NAME,
  97. &CLSID_LDAPUser, &IID_IADsUser },
  98. { TEXT("organizationalPerson"), USER_CLASS_NAME,
  99. &CLSID_LDAPUser, &IID_IADsUser },
  100. { TEXT("residentialPerson"), USER_CLASS_NAME,
  101. &CLSID_LDAPUser, &IID_IADsUser },
  102. { TEXT("groupOfNames"), GROUP_CLASS_NAME,
  103. &CLSID_LDAPGroup, &IID_IADsGroup },
  104. { TEXT("groupOfUniqueNames"), GROUP_CLASS_NAME,
  105. &CLSID_LDAPGroup, &IID_IADsGroup }
  106. // { TEXT("alias"), TEXT("Alias") },
  107. // ..other classes in RFC 1788 new
  108. };
  109. SYNTAXINFO g_aLDAPSyntax[] =
  110. { { TEXT("Boolean"), VT_BOOL },
  111. { TEXT("Counter"), VT_I4 },
  112. { TEXT("ADsPath"), VT_BSTR },
  113. { TEXT("EmailAddress"), VT_BSTR },
  114. { TEXT("FaxNumber"), VT_BSTR },
  115. { TEXT("Integer"), VT_I4 },
  116. { TEXT("Interval"), VT_I4 },
  117. { TEXT("List"), VT_VARIANT }, // VT_BSTR | VT_ARRAY
  118. { TEXT("NetAddress"), VT_BSTR },
  119. { TEXT("OctetString"), VT_VARIANT }, // VT_UI1| VT_ARRAY
  120. { TEXT("Path"), VT_BSTR },
  121. { TEXT("PhoneNumber"), VT_BSTR },
  122. { TEXT("PostalAddress"), VT_BSTR },
  123. { TEXT("SmallInterval"), VT_I4 },
  124. { TEXT("String"), VT_BSTR },
  125. { TEXT("Time"), VT_DATE },
  126. { TEXT("Integer8"), VT_DISPATCH },
  127. { TEXT("UTCTime"), VT_DATE },
  128. { TEXT("DN"), VT_BSTR },
  129. { TEXT("OID"), VT_BSTR },
  130. { TEXT("DirectoryString"), VT_BSTR },
  131. { TEXT("PrintableString"), VT_BSTR },
  132. { TEXT("CaseIgnoreString"), VT_BSTR },
  133. { TEXT("NumericString"), VT_BSTR },
  134. { TEXT("IA5String"), VT_BSTR },
  135. { TEXT("PresentationAddresses"), VT_BSTR },
  136. { TEXT("ORName"), VT_BSTR },
  137. { TEXT("DNWithBinary"), VT_DISPATCH },
  138. { TEXT("AccessPointDN"), VT_BSTR },
  139. { TEXT("DNWithString"), VT_DISPATCH },
  140. { TEXT("NTSecurityDescriptor"), VT_DISPATCH },
  141. { TEXT("ObjectSecurityDescriptor"), VT_DISPATCH },
  142. { TEXT("PresentationAddress"), VT_BSTR },
  143. { TEXT("GeneralizedTime"), VT_DATE },
  144. //
  145. // We do not support these
  146. // { TEXT("Enumeration")},
  147. // { TEXT("ReplicaLink") },
  148. // { TEXT("Sid") },
  149. { TEXT("CaseExactString"), VT_BSTR}
  150. };
  151. struct _OIDToNamemapping
  152. {
  153. LPTSTR pszAttributeTypeOID;
  154. LPTSTR pszFriendlyName;
  155. } aOIDtoNameMap[] =
  156. {
  157. { TEXT("1.2.840.113556.1.4.903"), TEXT("DNWithBinary") },
  158. { TEXT("1.2.840.113556.1.4.904"), TEXT("DNWithString") },
  159. // DnString also has the same OID as above
  160. { TEXT("1.2.840.113556.1.4.905"), TEXT("CaseIgnoreString") },
  161. { TEXT("1.2.840.113556.1.4.906"), TEXT("INTEGER8") },
  162. { TEXT("1.2.840.113556.1.4.907"), TEXT("ObjectSecurityDescriptor") },
  163. // the type is ORName a type of string -> mapped to string.
  164. { TEXT("1.2.840.113556.1.4.1221"), TEXT("ORName") },
  165. // the type is Undefined syntax in the server, so we are defaulting.
  166. { TEXT("1.2.840.113556.1.4.1222"), TEXT("Undefined") },
  167. { TEXT("1.2.840.113556.1.4.1362"), TEXT("CaseExactString") },
  168. { TEXT("1.3.6.1.4.1.1466.115.121.1.10"), TEXT("CertificatePair") }, // not in ours
  169. { TEXT("1.3.6.1.4.1.1466.115.121.1.11"), TEXT("CountryString") }, // not in ours
  170. { TEXT("1.3.6.1.4.1.1466.115.121.1.12"), TEXT("DN") },
  171. { TEXT("1.3.6.1.4.1.1466.115.121.1.13"), TEXT("DataQualitySyntax") }, // not in ours
  172. { TEXT("1.3.6.1.4.1.1466.115.121.1.14"), TEXT("DeliveryMethod") }, // not in ours
  173. { TEXT("1.3.6.1.4.1.1466.115.121.1.15"), TEXT("DirectoryString") },
  174. { TEXT("1.3.6.1.4.1.1466.115.121.1.19"), TEXT("DSAQualitySyntax") }, // not in ours
  175. { TEXT("1.3.6.1.4.1.1466.115.121.1.2"), TEXT("AccessPointDN") },
  176. { TEXT("1.3.6.1.4.1.1466.115.121.1.21"), TEXT("EmhancedGuide") }, // not in ours
  177. { TEXT("1.3.6.1.4.1.1466.115.121.1.22"), TEXT("FacsimileTelephoneNumber") }, // not in ours
  178. { TEXT("1.3.6.1.4.1.1466.115.121.1.23"), TEXT("Fax") }, // not in ours
  179. { TEXT("1.3.6.1.4.1.1466.115.121.1.24"), TEXT("GeneralizedTime") },
  180. { TEXT("1.3.6.1.4.1.1466.115.121.1.25"), TEXT("Guide") }, // not in ours
  181. { TEXT("1.3.6.1.4.1.1466.115.121.1.26"), TEXT("IA5String") },
  182. { TEXT("1.3.6.1.4.1.1466.115.121.1.27"), TEXT("INTEGER") },
  183. { TEXT("1.3.6.1.4.1.1466.115.121.1.28"), TEXT("JPEG") },// not in ours
  184. { TEXT("1.3.6.1.4.1.1466.115.121.1.3"), TEXT("AttributeTypeDescription") }, // not in ours
  185. { TEXT("1.3.6.1.4.1.1466.115.121.1.32"), TEXT("MailPreference") }, // not in ours
  186. { TEXT("1.3.6.1.4.1.1466.115.121.1.33"), TEXT("ORAddress") }, // not in ours
  187. { TEXT("1.3.6.1.4.1.1466.115.121.1.34"), TEXT("NameAndOptionalUID") }, // not in ours
  188. { TEXT("1.3.6.1.4.1.1466.115.121.1.36"), TEXT("NumericString") },
  189. { TEXT("1.3.6.1.4.1.1466.115.121.1.37"), TEXT("ObjectClassDescription") }, // not in ours
  190. { TEXT("1.3.6.1.4.1.1466.115.121.1.38"), TEXT("OID") },
  191. { TEXT("1.3.6.1.4.1.1466.115.121.1.39"), TEXT("OtherMailBox") }, // not in ours
  192. { TEXT("1.3.6.1.4.1.1466.115.121.1.4"), TEXT("Audio") }, // not in ours
  193. { TEXT("1.3.6.1.4.1.1466.115.121.1.40"), TEXT("OctetString") },
  194. { TEXT("1.3.6.1.4.1.1466.115.121.1.41"), TEXT("PostalAddress") },
  195. { TEXT("1.3.6.1.4.1.1466.115.121.1.43"), TEXT("PresentationAddress") },
  196. { TEXT("1.3.6.1.4.1.1466.115.121.1.44"), TEXT("PrintableString") },
  197. { TEXT("1.3.6.1.4.1.1466.115.121.1.5"), TEXT("OctetString") }, // not in ours we map to Octet
  198. { TEXT("1.3.6.1.4.1.1466.115.121.1.50"), TEXT("TelephoneNumber") }, // not in ours
  199. { TEXT("1.3.6.1.4.1.1466.115.121.1.51"), TEXT("TeletexTerminalIdentifier") }, // not in ours
  200. { TEXT("1.3.6.1.4.1.1466.115.121.1.52"), TEXT("TelexNumber") }, // not in ours
  201. { TEXT("1.3.6.1.4.1.1466.115.121.1.53"), TEXT("UTCTime") },
  202. { TEXT("1.3.6.1.4.1.1466.115.121.1.6"), TEXT("BitString") },
  203. { TEXT("1.3.6.1.4.1.1466.115.121.1.7"), TEXT("Boolean") },
  204. { TEXT("1.3.6.1.4.1.1466.115.121.1.8"), TEXT("Certificate") },
  205. { TEXT("1.3.6.1.4.1.1466.115.121.1.9"), TEXT("CertificateList") },
  206. };
  207. DWORD g_cLDAPSyntax = (sizeof(g_aLDAPSyntax)/sizeof(g_aLDAPSyntax[0]));
  208. typedef struct _classnamelist {
  209. LPTSTR pszClassName;
  210. _classnamelist *pNext;
  211. } CLASSNAME_LIST, *PCLASSNAME_LIST;
  212. BOOL
  213. GetSyntaxOID(
  214. LPTSTR pszSyntax,
  215. LPTSTR *ppszOID,
  216. DWORD *pdwOMSyntax
  217. )
  218. {
  219. for ( int i = 0; i < ARRAY_SIZE(aSyntaxMap); i++ )
  220. {
  221. if (_tcsicmp(pszSyntax, aSyntaxMap[i].pszSyntax) == 0 )
  222. {
  223. *ppszOID = aSyntaxMap[i].pszOID;
  224. *pdwOMSyntax = aSyntaxMap[i].dwOMSyntax;
  225. return TRUE;
  226. }
  227. }
  228. *ppszOID = NULL;
  229. return FALSE;
  230. }
  231. BOOL
  232. GetFriendlyNameFromOID(
  233. LPTSTR pszOID,
  234. LPTSTR *ppszFriendlyName
  235. )
  236. {
  237. HRESULT hr = S_OK;
  238. for ( int i = 0; i < ARRAY_SIZE(aOIDtoNameMap); i++ )
  239. {
  240. if ( _tcsicmp( pszOID, aOIDtoNameMap[i].pszAttributeTypeOID ) == 0 )
  241. {
  242. hr = ADsAllocString(
  243. aOIDtoNameMap[i].pszFriendlyName,
  244. ppszFriendlyName
  245. );
  246. if (SUCCEEDED(hr))
  247. return TRUE;
  248. else
  249. return FALSE;
  250. }
  251. }
  252. *ppszFriendlyName = NULL;
  253. return FALSE;
  254. }
  255. HRESULT
  256. MakeVariantFromStringArray(
  257. BSTR *bstrList,
  258. VARIANT *pvVariant
  259. );
  260. HRESULT
  261. MakeVariantFromPropStringTable(
  262. int *propList,
  263. LDAP_SCHEMA_HANDLE hSchema,
  264. VARIANT *pvVariant
  265. );
  266. HRESULT
  267. ConvertSafeArrayToVariantArray(
  268. VARIANT varSafeArray,
  269. PVARIANT *ppVarArray,
  270. PDWORD pdwNumVariants
  271. );
  272. /* No Longer needed
  273. HRESULT
  274. DeleteSchemaEntry(
  275. LPTSTR pszADsPath,
  276. LPTSTR pszRelativeName,
  277. LPTSTR pszClassName,
  278. LPTSTR pszSubSchemaSubEntry,
  279. CCredentials& Credentials
  280. );
  281. */
  282. HRESULT
  283. BuildSchemaLDAPPathAndGetAttribute(
  284. IN LPTSTR pszParent,
  285. IN LPTSTR pszClass,
  286. IN LPTSTR pszSubSchemaSubEntry,
  287. IN BOOL fNew,
  288. IN CCredentials& Credentials,
  289. IN LPTSTR pszAttribs[],
  290. OUT LPWSTR * ppszSchemaLDAPServer,
  291. OUT LPWSTR * ppszSchemaLDAPDn,
  292. IN OUT PADS_LDP *pLd,
  293. OUT LDAPMessage **ppRes
  294. );
  295. HRESULT
  296. BuildSchemaLDAPPath(
  297. LPTSTR pszParent,
  298. LPTSTR pszClass,
  299. LPTSTR pszSubSchemaSubEntry,
  300. LPWSTR * ppszSchemaLDAPServer,
  301. LPWSTR * ppszSchemaLDAPDn,
  302. BOOL fNew,
  303. ADS_LDP **pld,
  304. CCredentials& Credentials
  305. );
  306. HRESULT
  307. MakePropArrayFromVariant(
  308. VARIANT vProp,
  309. SCHEMAINFO *hSchema,
  310. int **pOIDs,
  311. DWORD *pNumOfOids
  312. );
  313. HRESULT
  314. MakePropArrayFromStringArray(
  315. LPTSTR *aValues,
  316. DWORD nCount,
  317. SCHEMAINFO *hSchema,
  318. int **pOIDs,
  319. DWORD *pNumOfOids
  320. );
  321. HRESULT
  322. SchemaGetPrimaryInterface(
  323. LDAP_SCHEMA_HANDLE hSchema,
  324. LPTSTR pszClassName,
  325. GUID **ppPrimaryInterfaceGUID,
  326. GUID **ppCLSID
  327. );
  328. STDMETHODIMP
  329. makeUnionVariantFromLdapObjects(
  330. LDAPOBJECTARRAY ldapSrcObjects1,
  331. LDAPOBJECTARRAY ldapSrcObjects2,
  332. VARIANT FAR * pvPossSuperiors
  333. );
  334. STDMETHODIMP
  335. addStringIfAbsent(
  336. BSTR addString,
  337. BSTR *strArray,
  338. PDWORD dwArrIndx
  339. );
  340. //
  341. // This functions puts the named string property into the cache
  342. // of the object as a CaseIgnoreString. It is meant for usage from
  343. // umi to put the simulated name property on schema objects.
  344. //
  345. HRESULT
  346. HelperPutStringPropertyInCache(
  347. LPWSTR pszName,
  348. LPWSTR pszStrProperty,
  349. CCredentials &Credentials,
  350. CPropertyCache *pPropCache
  351. )
  352. {
  353. HRESULT hr = E_NOTIMPL;
  354. DWORD dwIndex = 0;
  355. VARIANT varBstr;
  356. LDAPOBJECTARRAY ldapDestObjects;
  357. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  358. VariantInit(&varBstr);
  359. hr = ADsAllocString(pszStrProperty, &(varBstr.bstrVal));
  360. BAIL_ON_FAILURE(hr);
  361. varBstr.vt = VT_BSTR;
  362. //
  363. // Conver the variant to LDAP objects we can cache.
  364. //
  365. hr = VarTypeToLdapTypeCopyConstruct(
  366. NULL, //ServerName not needed here,
  367. Credentials,
  368. LDAPTYPE_CASEIGNORESTRING,
  369. &varBstr,
  370. 1,
  371. &ldapDestObjects
  372. );
  373. BAIL_ON_FAILURE(hr);
  374. //
  375. // Find this property in the cache
  376. //
  377. hr = pPropCache->findproperty(
  378. pszName,
  379. &dwIndex
  380. );
  381. //
  382. // If this property does not exist in the
  383. // cache, add this property into the cache.
  384. //
  385. if (FAILED(hr)) {
  386. hr = pPropCache->addproperty( pszName );
  387. BAIL_ON_FAILURE(hr);
  388. }
  389. //
  390. // Now update the property in the cache
  391. //
  392. hr = pPropCache->putproperty(
  393. pszName,
  394. PROPERTY_INIT,
  395. LDAPTYPE_CASEIGNORESTRING,
  396. ldapDestObjects
  397. );
  398. BAIL_ON_FAILURE(hr);
  399. error:
  400. VariantClear(&varBstr);
  401. LdapTypeFreeLdapObjects( &ldapDestObjects );
  402. RRETURN_EXP_IF_ERR(hr);
  403. }
  404. /******************************************************************/
  405. /* Class CLDAPSchema
  406. /******************************************************************/
  407. DEFINE_IDispatch_Implementation(CLDAPSchema)
  408. DEFINE_IADs_Implementation(CLDAPSchema)
  409. CLDAPSchema::CLDAPSchema()
  410. : _pDispMgr( NULL ),
  411. _pPropertyCache(NULL)
  412. {
  413. VariantInit( &_vFilter );
  414. VariantInit( &_vHints );
  415. _szServerPath[0] = 0;
  416. ENLIST_TRACKING(CLDAPSchema);
  417. }
  418. CLDAPSchema::~CLDAPSchema()
  419. {
  420. VariantClear( &_vFilter );
  421. VariantClear( &_vHints );
  422. delete _pDispMgr;
  423. delete _pPropertyCache;
  424. }
  425. HRESULT
  426. CLDAPSchema::CreateSchema(
  427. BSTR bstrParent,
  428. BSTR bstrName,
  429. LPTSTR pszServerPath,
  430. CCredentials& Credentials,
  431. DWORD dwObjectState,
  432. REFIID riid,
  433. void **ppvObj
  434. )
  435. {
  436. CLDAPSchema FAR *pSchema = NULL;
  437. HRESULT hr = S_OK;
  438. OBJECTINFO ObjectInfo;
  439. POBJECTINFO pObjectInfo = &ObjectInfo;
  440. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  441. hr = AllocateSchemaObject( &pSchema, Credentials );
  442. BAIL_ON_FAILURE(hr);
  443. _tcscpy( pSchema->_szServerPath, pszServerPath );
  444. hr = ADsObject(bstrParent, pObjectInfo);
  445. BAIL_ON_FAILURE(hr);
  446. pSchema->_dwPort = pObjectInfo->PortNumber;
  447. FreeObjectInfo(pObjectInfo);
  448. pObjectInfo = NULL;
  449. hr = pSchema->InitializeCoreObject(
  450. bstrParent,
  451. bstrName,
  452. SCHEMA_CLASS_NAME,
  453. CLSID_LDAPSchema,
  454. dwObjectState );
  455. BAIL_ON_FAILURE(hr);
  456. //
  457. // See if we need to create the Umi object.
  458. //
  459. if (Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
  460. hr = ((CCoreADsObject*)pSchema)->InitUmiObject(
  461. IntfPropsSchema,
  462. pSchema->_pPropertyCache,
  463. (IADs*) pSchema,
  464. (IADs*) pSchema,
  465. riid,
  466. ppvObj,
  467. &(pSchema->_Credentials),
  468. pSchema->_dwPort
  469. );
  470. BAIL_ON_FAILURE(hr);
  471. hr = HelperPutStringPropertyInCache(
  472. L"Name",
  473. bstrName,
  474. pSchema->_Credentials,
  475. pSchema->_pPropertyCache
  476. );
  477. BAIL_ON_FAILURE(hr);
  478. RRETURN(S_OK);
  479. }
  480. hr = pSchema->QueryInterface( riid, ppvObj );
  481. BAIL_ON_FAILURE(hr);
  482. pSchema->Release();
  483. RRETURN(hr);
  484. error:
  485. FreeObjectInfo(pObjectInfo);
  486. *ppvObj = NULL;
  487. delete pSchema;
  488. RRETURN_EXP_IF_ERR(hr);
  489. }
  490. STDMETHODIMP
  491. CLDAPSchema::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  492. {
  493. if (ppv == NULL) {
  494. RRETURN(E_POINTER);
  495. }
  496. if (IsEqualIID(iid, IID_IUnknown))
  497. {
  498. *ppv = (IADs FAR *) this;
  499. }
  500. else if (IsEqualIID(iid, IID_IDispatch))
  501. {
  502. *ppv = (IADs FAR *)this;
  503. }
  504. else if (IsEqualIID(iid, IID_IADs))
  505. {
  506. *ppv = (IADs FAR *) this;
  507. }
  508. else if (IsEqualIID(iid, IID_IADsContainer))
  509. {
  510. *ppv = (IADsContainer FAR *) this;
  511. }
  512. else if (IsEqualIID(iid, IID_ISupportErrorInfo))
  513. {
  514. *ppv = (ISupportErrorInfo FAR *) this;
  515. }
  516. else
  517. {
  518. *ppv = NULL;
  519. return E_NOINTERFACE;
  520. }
  521. AddRef();
  522. return NOERROR;
  523. }
  524. /* ISupportErrorInfo method */
  525. STDMETHODIMP
  526. CLDAPSchema::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
  527. {
  528. if (IsEqualIID(riid, IID_IADs) ||
  529. IsEqualIID(riid, IID_IADsContainer)) {
  530. RRETURN(S_OK);
  531. } else {
  532. RRETURN(S_FALSE);
  533. }
  534. }
  535. /* IADs methods */
  536. STDMETHODIMP
  537. CLDAPSchema::SetInfo(THIS)
  538. {
  539. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  540. }
  541. STDMETHODIMP
  542. CLDAPSchema::GetInfo(THIS)
  543. {
  544. HRESULT hr;
  545. hr = LDAPRefreshSchema();
  546. RRETURN_EXP_IF_ERR(hr);
  547. }
  548. //
  549. // Helper function for Umi - defined in CCoreADsObject.
  550. //
  551. STDMETHODIMP
  552. CLDAPSchema::GetInfo(DWORD dwFlags)
  553. {
  554. if (dwFlags == GETINFO_FLAG_EXPLICIT) {
  555. RRETURN(GetInfo());
  556. }
  557. //
  558. // All other cases we just say OK cause there is no way to go.
  559. //
  560. RRETURN(S_OK);
  561. }
  562. /* IADsContainer methods */
  563. STDMETHODIMP
  564. CLDAPSchema::get_Count(long FAR* retval)
  565. {
  566. HRESULT hr;
  567. DWORD nNumOfClasses;
  568. DWORD nNumOfProperties;
  569. if ( !retval )
  570. RRETURN(E_ADS_BAD_PARAMETER);
  571. hr = LdapGetSchemaObjectCount(
  572. _szServerPath,
  573. &nNumOfClasses,
  574. &nNumOfProperties,
  575. _Credentials,
  576. _dwPort
  577. );
  578. if ( SUCCEEDED(hr))
  579. *retval = nNumOfClasses + nNumOfProperties + g_cLDAPSyntax;
  580. RRETURN_EXP_IF_ERR(hr);
  581. }
  582. STDMETHODIMP
  583. CLDAPSchema::get_Filter(THIS_ VARIANT FAR* pVar)
  584. {
  585. if ( !pVar )
  586. RRETURN(E_ADS_BAD_PARAMETER);
  587. HRESULT hr;
  588. VariantInit( pVar );
  589. hr = VariantCopy( pVar, &_vFilter );
  590. RRETURN_EXP_IF_ERR(hr);
  591. }
  592. STDMETHODIMP
  593. CLDAPSchema::put_Filter(THIS_ VARIANT Var)
  594. {
  595. HRESULT hr;
  596. hr = VariantCopy( &_vFilter, &Var );
  597. RRETURN_EXP_IF_ERR(hr);
  598. }
  599. STDMETHODIMP
  600. CLDAPSchema::get_Hints(THIS_ VARIANT FAR* pVar)
  601. {
  602. if ( !pVar )
  603. RRETURN(E_ADS_BAD_PARAMETER);
  604. HRESULT hr;
  605. VariantInit( pVar );
  606. hr = VariantCopy( pVar, &_vHints );
  607. RRETURN_EXP_IF_ERR(hr);
  608. }
  609. STDMETHODIMP
  610. CLDAPSchema::put_Hints(THIS_ VARIANT Var)
  611. {
  612. HRESULT hr;
  613. VariantClear(&_vHints);
  614. hr = VariantCopy( &_vHints, &Var );
  615. RRETURN_EXP_IF_ERR(hr);
  616. }
  617. STDMETHODIMP
  618. CLDAPSchema::GetObject(
  619. THIS_ BSTR ClassName,
  620. BSTR RelativeName,
  621. IDispatch * FAR* ppObject)
  622. {
  623. DWORD dwBufferSize = 0;
  624. TCHAR *pszBuffer = NULL;
  625. HRESULT hr = S_OK;
  626. if (!RelativeName || !*RelativeName) {
  627. RRETURN(E_ADS_UNKNOWN_OBJECT);
  628. }
  629. dwBufferSize = ( _tcslen(_ADsPath) + _tcslen(RelativeName)
  630. + 2 ) * sizeof(TCHAR); // includes "/"
  631. pszBuffer = (LPTSTR) AllocADsMem( dwBufferSize );
  632. if ( pszBuffer == NULL )
  633. {
  634. hr = E_OUTOFMEMORY;
  635. BAIL_ON_FAILURE(hr);
  636. }
  637. _tcscpy(pszBuffer, _ADsPath);
  638. _tcscat(pszBuffer, TEXT("/"));
  639. _tcscat(pszBuffer, RelativeName);
  640. hr = ::GetObject(
  641. pszBuffer,
  642. _Credentials,
  643. (LPVOID *)ppObject
  644. );
  645. BAIL_ON_FAILURE(hr);
  646. error:
  647. if ( pszBuffer )
  648. FreeADsMem( pszBuffer );
  649. RRETURN_EXP_IF_ERR(hr);
  650. }
  651. STDMETHODIMP
  652. CLDAPSchema::get__NewEnum(THIS_ IUnknown * FAR* retval)
  653. {
  654. HRESULT hr;
  655. IEnumVARIANT *penum = NULL;
  656. if ( !retval )
  657. RRETURN(E_ADS_BAD_PARAMETER);
  658. *retval = NULL;
  659. //
  660. // Create new enumerator for items currently
  661. // in collection and QI for IUnknown
  662. //
  663. hr = CLDAPSchemaEnum::Create( (CLDAPSchemaEnum **)&penum,
  664. _ADsPath,
  665. _szServerPath,
  666. _vFilter,
  667. _Credentials
  668. );
  669. BAIL_ON_FAILURE(hr);
  670. hr = penum->QueryInterface( IID_IUnknown, (VOID FAR* FAR*)retval );
  671. BAIL_ON_FAILURE(hr);
  672. if ( penum )
  673. penum->Release();
  674. RRETURN(hr);
  675. error:
  676. if ( penum )
  677. delete penum;
  678. RRETURN_EXP_IF_ERR(hr);
  679. }
  680. STDMETHODIMP
  681. CLDAPSchema::Create(
  682. THIS_ BSTR ClassName,
  683. BSTR RelativeName,
  684. IDispatch * FAR* ppObject)
  685. {
  686. HRESULT hr = S_OK;
  687. LDAP_SCHEMA_HANDLE hSchema = NULL;
  688. hr = SchemaOpen( _szServerPath, &hSchema, _Credentials, _dwPort );
  689. BAIL_ON_FAILURE(hr);
  690. //
  691. // We can only create "Class","Property" here, "Syntax" is read-only
  692. //
  693. if ( ( _tcsicmp( ClassName, CLASS_CLASS_NAME ) == 0 )
  694. || ( _tcsicmp( ClassName, NT_SCHEMA_CLASS_NAME ) == 0 )
  695. )
  696. {
  697. //
  698. // Now, create the class
  699. //
  700. hr = CLDAPClass::CreateClass(
  701. _ADsPath,
  702. hSchema,
  703. RelativeName,
  704. NULL,
  705. _Credentials,
  706. ADS_OBJECT_UNBOUND,
  707. IID_IUnknown,
  708. (void **) ppObject );
  709. }
  710. else if ( ( _tcsicmp( ClassName, PROPERTY_CLASS_NAME ) == 0 )
  711. || ( _tcsicmp( ClassName, NT_SCHEMA_PROPERTY_NAME ) == 0 )
  712. )
  713. {
  714. hr = CLDAPProperty::CreateProperty(
  715. _ADsPath,
  716. hSchema,
  717. RelativeName,
  718. NULL,
  719. _Credentials,
  720. ADS_OBJECT_UNBOUND,
  721. IID_IUnknown,
  722. (void **) ppObject );
  723. }
  724. else
  725. {
  726. hr = E_ADS_BAD_PARAMETER;
  727. }
  728. error:
  729. if ( hSchema )
  730. SchemaClose( &hSchema );
  731. RRETURN_EXP_IF_ERR(hr);
  732. }
  733. STDMETHODIMP
  734. CLDAPSchema::Delete(THIS_ BSTR bstrClassName, BSTR bstrRelativeName )
  735. {
  736. RRETURN(E_NOTIMPL);
  737. }
  738. STDMETHODIMP
  739. CLDAPSchema::CopyHere(THIS_ BSTR SourceName,
  740. BSTR NewName,
  741. IDispatch * FAR* ppObject)
  742. {
  743. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  744. }
  745. STDMETHODIMP
  746. CLDAPSchema::MoveHere(THIS_ BSTR SourceName,
  747. BSTR NewName,
  748. IDispatch * FAR* ppObject)
  749. {
  750. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  751. }
  752. STDMETHODIMP
  753. CLDAPSchema::Get(THIS_ BSTR bstrName, VARIANT FAR* pvProp)
  754. {
  755. HRESULT hr = S_OK;
  756. LPTSTR pszSubSchemaSubEntry = NULL;
  757. LPTSTR pszSchemaRoot = NULL;
  758. //
  759. // For folks who know now what they do.
  760. //
  761. if (!pvProp) {
  762. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  763. }
  764. VariantInit( pvProp );
  765. // Temporary hack
  766. if ( _tcsicmp( bstrName, TEXT("NTSchemaPath")) == 0 )
  767. {
  768. hr = LdapGetSubSchemaSubEntryPath(
  769. _szServerPath,
  770. &pszSubSchemaSubEntry,
  771. _Credentials,
  772. _dwPort
  773. );
  774. BAIL_ON_FAILURE(hr);
  775. if ( pszSubSchemaSubEntry == NULL ) // not NTDS server
  776. {
  777. hr = E_NOTIMPL;
  778. BAIL_ON_FAILURE(hr);
  779. }
  780. // the _tcschr is to get rid of "CN=Aggregate"
  781. pszSchemaRoot = _tcschr(pszSubSchemaSubEntry, TEXT(','));
  782. if ( pszSchemaRoot == NULL ) // not NTDS server
  783. {
  784. hr = E_NOTIMPL;
  785. BAIL_ON_FAILURE(hr);
  786. }
  787. hr = ADsAllocString( pszSchemaRoot + 1,
  788. &(pvProp->bstrVal));
  789. BAIL_ON_FAILURE(hr);
  790. pvProp->vt = VT_BSTR;
  791. }
  792. else
  793. {
  794. hr = E_NOTIMPL;
  795. }
  796. error:
  797. if ( pszSubSchemaSubEntry )
  798. FreeADsStr( pszSubSchemaSubEntry );
  799. if ( FAILED(hr))
  800. VariantClear( pvProp );
  801. RRETURN_EXP_IF_ERR(hr);
  802. }
  803. STDMETHODIMP
  804. CLDAPSchema::Put(THIS_ BSTR bstrName, VARIANT vProp)
  805. {
  806. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  807. }
  808. STDMETHODIMP
  809. CLDAPSchema::GetEx(THIS_ BSTR bstrName, VARIANT FAR* pvProp)
  810. {
  811. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  812. }
  813. STDMETHODIMP
  814. CLDAPSchema::PutEx(THIS_ long lnControlCode, BSTR bstrName, VARIANT vProp)
  815. {
  816. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  817. }
  818. STDMETHODIMP
  819. CLDAPSchema::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
  820. {
  821. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  822. }
  823. HRESULT
  824. CLDAPSchema::AllocateSchemaObject(
  825. CLDAPSchema FAR * FAR * ppSchema,
  826. CCredentials& Credentials
  827. )
  828. {
  829. CLDAPSchema FAR *pSchema = NULL;
  830. CAggregatorDispMgr FAR *pDispMgr = NULL;
  831. CPropertyCache FAR *pPropertyCache = NULL;
  832. HRESULT hr = S_OK;
  833. pSchema = new CLDAPSchema();
  834. if ( pSchema == NULL )
  835. hr = E_OUTOFMEMORY;
  836. BAIL_ON_FAILURE(hr);
  837. pDispMgr = new CAggregatorDispMgr(Credentials);
  838. if ( pDispMgr == NULL )
  839. hr = E_OUTOFMEMORY;
  840. BAIL_ON_FAILURE(hr);
  841. hr = pDispMgr->LoadTypeInfoEntry(
  842. LIBID_ADs,
  843. IID_IADs,
  844. (IADs *) pSchema,
  845. DISPID_REGULAR );
  846. BAIL_ON_FAILURE(hr);
  847. hr = pDispMgr->LoadTypeInfoEntry(
  848. LIBID_ADs,
  849. IID_IADsContainer,
  850. (IADsContainer *) pSchema,
  851. DISPID_NEWENUM );
  852. BAIL_ON_FAILURE(hr);
  853. hr = CPropertyCache::createpropertycache(
  854. (CCoreADsObject FAR *) pSchema,
  855. (IGetAttributeSyntax *) pSchema,
  856. &pPropertyCache
  857. );
  858. BAIL_ON_FAILURE(hr);
  859. pSchema->_pPropertyCache = pPropertyCache;
  860. pSchema->_Credentials = Credentials;
  861. pSchema->_pDispMgr = pDispMgr;
  862. *ppSchema = pSchema;
  863. RRETURN(hr);
  864. error:
  865. delete pDispMgr;
  866. delete pSchema;
  867. delete pPropertyCache;
  868. RRETURN(hr);
  869. }
  870. HRESULT
  871. CLDAPSchema::LDAPRefreshSchema(THIS)
  872. {
  873. HRESULT hr = S_OK;
  874. //
  875. // Make the old schema obsolete.
  876. // We cannot delete the old schema since other objects might have
  877. // references to it.
  878. //
  879. hr = LdapMakeSchemaCacheObsolete(
  880. _szServerPath,
  881. _Credentials,
  882. _dwPort
  883. );
  884. RRETURN_EXP_IF_ERR(hr);
  885. }
  886. //
  887. // Needed for dynamic dispid's in the property cache.
  888. //
  889. HRESULT
  890. CLDAPSchema::GetAttributeSyntax(
  891. LPWSTR szPropertyName,
  892. PDWORD pdwSyntaxId
  893. )
  894. {
  895. HRESULT hr = S_OK;
  896. if ((_Credentials.GetAuthFlags() & ADS_AUTH_RESERVED)
  897. && !_wcsicmp(L"Name", szPropertyName)) {
  898. *pdwSyntaxId = LDAPTYPE_CASEIGNORESTRING;
  899. }
  900. else {
  901. hr = E_ADS_PROPERTY_NOT_FOUND;
  902. }
  903. RRETURN_EXP_IF_ERR(hr);
  904. }
  905. /******************************************************************/
  906. /* Class CLDAPClass
  907. /******************************************************************/
  908. DEFINE_IDispatch_Implementation(CLDAPClass)
  909. DEFINE_IADs_Implementation(CLDAPClass)
  910. CLDAPClass::CLDAPClass()
  911. : _pDispMgr( NULL ),
  912. _pPropertyCache( NULL ),
  913. _bstrCLSID( NULL ),
  914. _bstrPrimaryInterface( NULL ),
  915. _bstrHelpFileName( NULL ),
  916. _lHelpFileContext( 0 ),
  917. _hSchema( NULL ),
  918. _pClassInfo( NULL ),
  919. _fNTDS( TRUE ),
  920. _pszLDAPServer(NULL),
  921. _pszLDAPDn(NULL),
  922. _ld( NULL ),
  923. _fLoadedInterfaceInfo(FALSE)
  924. {
  925. ENLIST_TRACKING(CLDAPClass);
  926. }
  927. CLDAPClass::~CLDAPClass()
  928. {
  929. delete _pDispMgr;
  930. delete _pPropertyCache;
  931. if ( _bstrCLSID ) {
  932. ADsFreeString( _bstrCLSID );
  933. }
  934. if ( _bstrPrimaryInterface ) {
  935. ADsFreeString( _bstrPrimaryInterface );
  936. }
  937. if ( _bstrHelpFileName ) {
  938. ADsFreeString( _bstrHelpFileName );
  939. }
  940. if ( _hSchema ) {
  941. SchemaClose( &_hSchema );
  942. _hSchema = NULL;
  943. }
  944. if ( _pszLDAPServer ) {
  945. FreeADsStr( _pszLDAPServer );
  946. }
  947. if (_pszLDAPDn) {
  948. FreeADsStr(_pszLDAPDn);
  949. }
  950. if ( _ld ) {
  951. LdapCloseObject( _ld );
  952. _ld = NULL;
  953. }
  954. }
  955. HRESULT
  956. CLDAPClass::CreateClass(
  957. BSTR bstrParent,
  958. LDAP_SCHEMA_HANDLE hSchema,
  959. BSTR bstrName,
  960. CLASSINFO *pClassInfo,
  961. CCredentials& Credentials,
  962. DWORD dwObjectState,
  963. REFIID riid,
  964. void **ppvObj
  965. )
  966. {
  967. CLDAPClass FAR *pClass = NULL;
  968. HRESULT hr = S_OK;
  969. BOOL fUmiCall = FALSE;
  970. OBJECTINFO ObjectInfo;
  971. POBJECTINFO pObjectInfo = &ObjectInfo;
  972. VARIANT var;
  973. VariantInit(&var);
  974. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  975. hr = AllocateClassObject(Credentials, &pClass );
  976. BAIL_ON_FAILURE(hr);
  977. //
  978. // Some extra things need to be done if the call is from umi.
  979. //
  980. fUmiCall = Credentials.GetAuthFlags() & ADS_AUTH_RESERVED;
  981. pClass->_pClassInfo = pClassInfo;
  982. SchemaAddRef( hSchema );
  983. pClass->_hSchema = hSchema;
  984. if ( pClassInfo ) // an existing class
  985. {
  986. if ( pClassInfo->pszHelpFileName )
  987. {
  988. hr = ADsAllocString( pClassInfo->pszHelpFileName,
  989. &pClass->_bstrHelpFileName );
  990. }
  991. pClass->_lHelpFileContext = pClassInfo->lHelpFileContext;
  992. hr = put_BSTR_Property( pClass, TEXT("governsID"), pClassInfo->pszOID);
  993. if ( SUCCEEDED(hr))
  994. {
  995. hr = put_LONG_Property( pClass, TEXT("objectClassCategory"),
  996. pClassInfo->dwType );
  997. BAIL_ON_FAILURE(hr);
  998. VariantInit( &var );
  999. hr = MakeVariantFromPropStringTable( pClassInfo->pOIDsMustContain,
  1000. pClass->_hSchema,
  1001. &var );
  1002. BAIL_ON_FAILURE(hr);
  1003. hr = put_VARIANT_Property( pClass, TEXT("mustContain"), var );
  1004. BAIL_ON_FAILURE(hr);
  1005. if (fUmiCall) {
  1006. //
  1007. // Need to add this to the cache as mandatoryProperties.
  1008. //
  1009. hr = put_VARIANT_Property(
  1010. pClass,
  1011. TEXT("mandatoryProperties"),
  1012. var
  1013. );
  1014. BAIL_ON_FAILURE(hr);
  1015. //
  1016. // We also need a dummy property called Name.
  1017. //
  1018. hr = put_BSTR_Property(
  1019. pClass,
  1020. TEXT("Name"),
  1021. bstrName
  1022. );
  1023. BAIL_ON_FAILURE(hr);
  1024. }
  1025. VariantClear( &var );
  1026. hr = MakeVariantFromPropStringTable( pClassInfo->pOIDsMayContain,
  1027. pClass->_hSchema,
  1028. &var );
  1029. BAIL_ON_FAILURE(hr);
  1030. hr = put_VARIANT_Property( pClass, TEXT("mayContain"), var );
  1031. BAIL_ON_FAILURE(hr);
  1032. if (fUmiCall) {
  1033. //
  1034. // Again need to add as optionalProperties.
  1035. //
  1036. hr = put_VARIANT_Property(
  1037. pClass,
  1038. TEXT("optionalProperties"),
  1039. var
  1040. );
  1041. BAIL_ON_FAILURE(hr);
  1042. }
  1043. VariantClear( &var );
  1044. hr = MakeVariantFromStringArray( pClassInfo->pOIDsSuperiorClasses,
  1045. &var );
  1046. BAIL_ON_FAILURE(hr);
  1047. hr = put_VARIANT_Property( pClass, TEXT("subClassOf"), var );
  1048. BAIL_ON_FAILURE(hr);
  1049. VariantClear( &var );
  1050. hr = MakeVariantFromStringArray( pClassInfo->pOIDsAuxClasses,
  1051. &var );
  1052. BAIL_ON_FAILURE(hr);
  1053. hr = put_VARIANT_Property( pClass, TEXT("auxiliaryClass"), var );
  1054. BAIL_ON_FAILURE(hr);
  1055. VariantClear( &var );
  1056. pClass->_pPropertyCache->ClearAllPropertyFlags();
  1057. pClass->_fNTDS = TRUE;
  1058. }
  1059. else
  1060. {
  1061. pClass->_fNTDS = FALSE;
  1062. }
  1063. }
  1064. hr = ADsObject(bstrParent, pObjectInfo);
  1065. BAIL_ON_FAILURE(hr);
  1066. pClass->_dwPort = pObjectInfo->PortNumber;
  1067. FreeObjectInfo(pObjectInfo);
  1068. pObjectInfo = NULL;
  1069. hr = pClass->InitializeCoreObject(
  1070. bstrParent,
  1071. bstrName,
  1072. CLASS_CLASS_NAME,
  1073. CLSID_LDAPClass,
  1074. dwObjectState );
  1075. BAIL_ON_FAILURE(hr);
  1076. //
  1077. // At this point update the info in the property cache
  1078. //
  1079. pClass->_pPropertyCache->SetObjInformation(
  1080. &(pClass->_Credentials),
  1081. pClass->_pszLDAPServer,
  1082. pClass->_dwPort
  1083. );
  1084. BAIL_ON_FAILURE(hr);
  1085. //
  1086. // If this is a umi call we need to return umi object.
  1087. //
  1088. if (fUmiCall) {
  1089. hr = ((CCoreADsObject*)pClass)->InitUmiObject(
  1090. IntfPropsSchema,
  1091. pClass->_pPropertyCache,
  1092. (IADs *) pClass,
  1093. (IADs *) pClass,
  1094. riid,
  1095. ppvObj,
  1096. &(pClass->_Credentials),
  1097. pClass->_dwPort,
  1098. pClass->_pszLDAPServer,
  1099. pClass->_pszLDAPDn
  1100. );
  1101. BAIL_ON_FAILURE(hr);
  1102. RRETURN(S_OK);
  1103. }
  1104. hr = pClass->QueryInterface( riid, ppvObj );
  1105. BAIL_ON_FAILURE(hr);
  1106. pClass->Release();
  1107. RRETURN(hr);
  1108. error:
  1109. *ppvObj = NULL;
  1110. delete pClass;
  1111. VariantClear(&var);
  1112. FreeObjectInfo(pObjectInfo);
  1113. RRETURN_EXP_IF_ERR(hr);
  1114. }
  1115. STDMETHODIMP
  1116. CLDAPClass::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  1117. {
  1118. if (ppv == NULL) {
  1119. RRETURN(E_POINTER);
  1120. }
  1121. if (IsEqualIID(iid, IID_IUnknown))
  1122. {
  1123. *ppv = (IADsClass FAR * ) this;
  1124. }
  1125. else if (IsEqualIID(iid, IID_IDispatch))
  1126. {
  1127. *ppv = (IADs FAR *) this;
  1128. }
  1129. else if (IsEqualIID(iid, IID_ISupportErrorInfo))
  1130. {
  1131. *ppv = (ISupportErrorInfo FAR *) this;
  1132. }
  1133. else if (IsEqualIID(iid, IID_IADs))
  1134. {
  1135. *ppv = (IADs FAR *) this;
  1136. }
  1137. else if (IsEqualIID(iid, IID_IADsClass))
  1138. {
  1139. *ppv = (IADsClass FAR *) this;
  1140. }
  1141. else if (IsEqualIID(iid, IID_IADsUmiHelperPrivate)) {
  1142. *ppv = (IADsUmiHelperPrivate FAR *) this;
  1143. }
  1144. else
  1145. {
  1146. *ppv = NULL;
  1147. return E_NOINTERFACE;
  1148. }
  1149. AddRef();
  1150. return NOERROR;
  1151. }
  1152. /* ISupportErrorInfo method */
  1153. STDMETHODIMP
  1154. CLDAPClass::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
  1155. {
  1156. if (IsEqualIID(riid, IID_IADs) ||
  1157. IsEqualIID(riid, IID_IADsClass)) {
  1158. RRETURN(S_OK);
  1159. } else {
  1160. RRETURN(S_FALSE);
  1161. }
  1162. }
  1163. /* IADs methods */
  1164. STDMETHODIMP
  1165. CLDAPClass::SetInfo(THIS)
  1166. {
  1167. HRESULT hr = S_OK;
  1168. BOOL fChanged = FALSE;
  1169. if ( !_fNTDS )
  1170. RRETURN(E_NOTIMPL);
  1171. if ( GetObjectState() == ADS_OBJECT_UNBOUND )
  1172. {
  1173. hr = LDAPCreateObject();
  1174. BAIL_ON_FAILURE(hr);
  1175. fChanged = TRUE;
  1176. //
  1177. // If the create succeded, set the object type to bound
  1178. //
  1179. SetObjectState(ADS_OBJECT_BOUND);
  1180. }
  1181. else
  1182. {
  1183. hr = LDAPSetObject( &fChanged );
  1184. BAIL_ON_FAILURE(hr);
  1185. }
  1186. //
  1187. // Need to refresh the schema
  1188. //
  1189. if ( SUCCEEDED(hr) && fChanged )
  1190. hr = LDAPRefreshSchema();
  1191. error:
  1192. RRETURN_EXP_IF_ERR(hr);
  1193. }
  1194. HRESULT
  1195. CLDAPClass::LDAPSetObject( BOOL *pfChanged )
  1196. {
  1197. HRESULT hr = S_OK;
  1198. BOOL fUpdated = FALSE;
  1199. BOOL fUpdateMustContain = FALSE;
  1200. BOOL fUpdateMayContain = FALSE;
  1201. VARIANT var;
  1202. int *pOIDs = NULL;
  1203. DWORD nNumOfOids = 0;
  1204. LDAPModW **aMod = NULL;
  1205. DWORD dwNumOfMods = 0;
  1206. DWORD dwNumOfModsNeedFreeing = 0;
  1207. *pfChanged = FALSE;
  1208. hr = _pPropertyCache->IsPropertyUpdated( TEXT("mustContain"), &fUpdated);
  1209. BAIL_ON_FAILURE(hr);
  1210. if ( fUpdated )
  1211. {
  1212. VariantInit(&var);
  1213. hr = get_VARIANT_Property( this, TEXT("mustContain"), &var );
  1214. BAIL_ON_FAILURE(hr);
  1215. hr = MakePropArrayFromVariant( var,
  1216. (SCHEMAINFO *) _hSchema,
  1217. &pOIDs,
  1218. &nNumOfOids );
  1219. BAIL_ON_FAILURE(hr);
  1220. hr = FindModifications( pOIDs,
  1221. nNumOfOids,
  1222. TEXT("mustContain"),
  1223. &aMod,
  1224. &dwNumOfMods );
  1225. BAIL_ON_FAILURE(hr);
  1226. // This flag needs to be cleared temporarily so that
  1227. // LDAPMarshallProperties2 below will not try to update
  1228. // this property. We will reset the flag right later.
  1229. hr = _pPropertyCache->ClearPropertyFlag( TEXT("mustContain"));
  1230. BAIL_ON_FAILURE(hr);
  1231. fUpdateMustContain = TRUE;
  1232. VariantClear(&var);
  1233. FreeADsMem( pOIDs );
  1234. pOIDs = NULL;
  1235. }
  1236. hr = _pPropertyCache->IsPropertyUpdated( TEXT("mayContain"), &fUpdated);
  1237. BAIL_ON_FAILURE(hr);
  1238. if ( fUpdated )
  1239. {
  1240. VariantInit(&var);
  1241. hr = get_VARIANT_Property( this, TEXT("mayContain"), &var );
  1242. BAIL_ON_FAILURE(hr);
  1243. hr = MakePropArrayFromVariant( var,
  1244. (SCHEMAINFO *) _hSchema,
  1245. &pOIDs,
  1246. &nNumOfOids );
  1247. BAIL_ON_FAILURE(hr);
  1248. hr = FindModifications( pOIDs,
  1249. nNumOfOids,
  1250. TEXT("mayContain"),
  1251. &aMod,
  1252. &dwNumOfMods );
  1253. BAIL_ON_FAILURE(hr);
  1254. // This flag needs to be cleared temporarily so that
  1255. // LDAPMarshallProperties2 below will not try to update
  1256. // this property. We will reset the flag later on.
  1257. hr = _pPropertyCache->ClearPropertyFlag( TEXT("mayContain"));
  1258. BAIL_ON_FAILURE(hr);
  1259. fUpdateMayContain = TRUE;
  1260. VariantClear(&var);
  1261. FreeADsMem( pOIDs );
  1262. pOIDs = NULL;
  1263. }
  1264. dwNumOfModsNeedFreeing = dwNumOfMods;
  1265. hr = _pPropertyCache->LDAPMarshallProperties2(
  1266. &aMod,
  1267. &dwNumOfMods
  1268. );
  1269. BAIL_ON_FAILURE(hr);
  1270. if ( aMod == NULL ) // There are no changes that needs to be modified
  1271. RRETURN(S_OK);
  1272. //
  1273. // Reset the flags so that if LdapModifyS fails, they are still flagged
  1274. // as needed to be updated.
  1275. //
  1276. if ( fUpdateMustContain )
  1277. {
  1278. hr = _pPropertyCache->SetPropertyFlag( TEXT("mustContain"),
  1279. PROPERTY_UPDATE );
  1280. BAIL_ON_FAILURE(hr);
  1281. }
  1282. if ( fUpdateMayContain )
  1283. {
  1284. hr = _pPropertyCache->SetPropertyFlag( TEXT("mayContain"),
  1285. PROPERTY_UPDATE );
  1286. BAIL_ON_FAILURE(hr);
  1287. }
  1288. //
  1289. // Send the request to the server
  1290. //
  1291. if (_pszLDAPDn == NULL )
  1292. {
  1293. hr = BuildSchemaLDAPPath( _Parent,
  1294. _Name,
  1295. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  1296. &_pszLDAPServer,
  1297. &_pszLDAPDn,
  1298. _pClassInfo == NULL,
  1299. &_ld,
  1300. _Credentials
  1301. );
  1302. BAIL_ON_FAILURE(hr);
  1303. }
  1304. hr = LdapModifyS(
  1305. _ld,
  1306. _pszLDAPDn,
  1307. aMod
  1308. );
  1309. BAIL_ON_FAILURE(hr);
  1310. // We are successful at this point,
  1311. // So, clean up the flags in the cache so the same operation
  1312. // won't be repeated on the next SetInfo()
  1313. _pPropertyCache->ClearAllPropertyFlags();
  1314. *pfChanged = TRUE;
  1315. error:
  1316. VariantClear(&var);
  1317. if ( pOIDs )
  1318. FreeADsMem( pOIDs );
  1319. if (aMod) {
  1320. for ( DWORD i = 0; i < dwNumOfModsNeedFreeing; i++ )
  1321. {
  1322. FreeADsMem((*aMod)[i].mod_values);
  1323. }
  1324. if ( *aMod )
  1325. FreeADsMem( *aMod );
  1326. FreeADsMem( aMod );
  1327. }
  1328. RRETURN_EXP_IF_ERR(hr);
  1329. }
  1330. HRESULT
  1331. CLDAPClass::LDAPCreateObject()
  1332. {
  1333. HRESULT hr = S_OK;
  1334. LDAPModW **aMod = NULL;
  1335. DWORD dwIndex = 0;
  1336. VARIANT v;
  1337. BOOL fNTSecDes = FALSE;
  1338. SECURITY_INFORMATION NewSeInfo;
  1339. //
  1340. // Get the LDAP path of the schema entry
  1341. //
  1342. if (_pszLDAPDn == NULL )
  1343. {
  1344. hr = BuildSchemaLDAPPath( _Parent,
  1345. _Name,
  1346. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  1347. &_pszLDAPServer,
  1348. &_pszLDAPDn,
  1349. _pClassInfo == NULL,
  1350. &_ld,
  1351. _Credentials
  1352. );
  1353. BAIL_ON_FAILURE(hr);
  1354. }
  1355. if ( _pPropertyCache->findproperty( TEXT("objectClass"), &dwIndex )
  1356. == E_ADS_PROPERTY_NOT_FOUND )
  1357. {
  1358. VariantInit(&v);
  1359. v.vt = VT_BSTR;
  1360. V_BSTR(&v) = NT_SCHEMA_CLASS_NAME;
  1361. hr = Put( TEXT("objectClass"), v );
  1362. BAIL_ON_FAILURE(hr);
  1363. }
  1364. if ( _pPropertyCache->findproperty( TEXT("cn"), &dwIndex )
  1365. == E_ADS_PROPERTY_NOT_FOUND )
  1366. {
  1367. VariantInit(&v);
  1368. v.vt = VT_BSTR;
  1369. V_BSTR(&v) = _Name;
  1370. hr = Put( TEXT("cn"), v );
  1371. BAIL_ON_FAILURE(hr);
  1372. }
  1373. if ( _pPropertyCache->findproperty( TEXT("lDAPDisplayName"), &dwIndex )
  1374. == E_ADS_PROPERTY_NOT_FOUND )
  1375. {
  1376. VariantInit(&v);
  1377. v.vt = VT_BSTR;
  1378. V_BSTR(&v) = _Name;
  1379. hr = Put( TEXT("lDAPDisplayName"), v );
  1380. BAIL_ON_FAILURE(hr);
  1381. }
  1382. if ( _pPropertyCache->findproperty( TEXT("objectClassCategory"), &dwIndex)
  1383. == E_ADS_PROPERTY_NOT_FOUND )
  1384. {
  1385. VariantInit(&v);
  1386. v.vt = VT_I4;
  1387. V_I4(&v) = CLASS_TYPE_STRUCTURAL;
  1388. hr = Put( TEXT("objectClassCategory"), v );
  1389. BAIL_ON_FAILURE(hr);
  1390. }
  1391. hr = _pPropertyCache->LDAPMarshallProperties(
  1392. &aMod,
  1393. &fNTSecDes,
  1394. &NewSeInfo
  1395. );
  1396. BAIL_ON_FAILURE(hr);
  1397. if ( _ld == NULL )
  1398. {
  1399. hr = LdapOpenObject(
  1400. _pszLDAPServer,
  1401. _pszLDAPDn,
  1402. &_ld,
  1403. _Credentials,
  1404. _dwPort
  1405. );
  1406. BAIL_ON_FAILURE(hr);
  1407. }
  1408. hr = LdapAddS(
  1409. _ld,
  1410. _pszLDAPDn,
  1411. aMod
  1412. );
  1413. BAIL_ON_FAILURE(hr);
  1414. // We are successful at this point,
  1415. // So, clean up the flags in the cache so the same operation
  1416. // won't be repeated on the next SetInfo()
  1417. _pPropertyCache->ClearAllPropertyFlags();
  1418. error:
  1419. if (aMod) {
  1420. if ( *aMod )
  1421. FreeADsMem( *aMod );
  1422. FreeADsMem( aMod );
  1423. }
  1424. RRETURN_EXP_IF_ERR(hr);
  1425. }
  1426. HRESULT
  1427. CLDAPClass::LDAPRefreshSchema(THIS)
  1428. {
  1429. HRESULT hr = S_OK;
  1430. TCHAR *pszLDAPServer = NULL;
  1431. TCHAR *pszLDAPDn = NULL;
  1432. DWORD dwPort = 0;
  1433. //
  1434. // Get the server name
  1435. //
  1436. hr = BuildLDAPPathFromADsPath2(
  1437. _Parent,
  1438. &pszLDAPServer,
  1439. &pszLDAPDn,
  1440. &dwPort
  1441. );
  1442. BAIL_ON_FAILURE(hr);
  1443. //
  1444. // Make the old schema obsolete so we will get the new schema next
  1445. // time we asked for it.
  1446. // We cannot delete the old schema since other objects might have
  1447. // references to it.
  1448. //
  1449. hr = LdapMakeSchemaCacheObsolete(
  1450. pszLDAPServer,
  1451. _Credentials,
  1452. _dwPort
  1453. );
  1454. BAIL_ON_FAILURE(hr);
  1455. error:
  1456. if (pszLDAPServer) {
  1457. FreeADsStr(pszLDAPServer);
  1458. }
  1459. if (pszLDAPDn) {
  1460. FreeADsStr(pszLDAPDn);
  1461. }
  1462. RRETURN_EXP_IF_ERR(hr);
  1463. }
  1464. STDMETHODIMP
  1465. CLDAPClass::GetInfo(THIS)
  1466. {
  1467. HRESULT hr = S_OK;
  1468. VARIANT var;
  1469. BOOL fUmiCall = FALSE;
  1470. LPWSTR pszLDAPServer = NULL;
  1471. LPWSTR pszLDAPDn = NULL;
  1472. DWORD dwPort = 0;
  1473. VariantInit(&var);
  1474. if ( GetObjectState() == ADS_OBJECT_UNBOUND )
  1475. RRETURN(E_ADS_OBJECT_UNBOUND);
  1476. //
  1477. // Update the umicall flag - we need to add items to prop cache
  1478. // if the call is from Umi.
  1479. //
  1480. fUmiCall = _Credentials.GetAuthFlags() & ADS_AUTH_RESERVED;
  1481. //
  1482. // Get the server name
  1483. //
  1484. hr = BuildLDAPPathFromADsPath2(
  1485. _Parent,
  1486. &pszLDAPServer,
  1487. &pszLDAPDn,
  1488. &dwPort
  1489. );
  1490. BAIL_ON_FAILURE(hr);
  1491. //
  1492. // AjayR - 04-05-99 do not understand why this is done
  1493. // I do not think you need to obsolete the cache on the
  1494. // GetInfo for a class - for the schema container yes.
  1495. //
  1496. hr = LdapMakeSchemaCacheObsolete(
  1497. pszLDAPServer,
  1498. _Credentials,
  1499. dwPort
  1500. );
  1501. BAIL_ON_FAILURE(hr);
  1502. //
  1503. // Release the original schema info
  1504. //
  1505. SchemaClose( &_hSchema );
  1506. //
  1507. // Get the new schema info
  1508. //
  1509. hr = SchemaOpen(
  1510. pszLDAPServer,
  1511. &_hSchema,
  1512. _Credentials,
  1513. _dwPort // IsGCNamespace(_Parent)
  1514. );
  1515. BAIL_ON_FAILURE(hr);
  1516. //
  1517. // Find the new class info
  1518. //
  1519. hr = SchemaGetClassInfo(
  1520. _hSchema,
  1521. _Name,
  1522. &_pClassInfo );
  1523. BAIL_ON_FAILURE( hr );
  1524. if ( _pClassInfo == NULL )
  1525. {
  1526. // Class name not found, set error
  1527. hr = E_ADS_BAD_PATHNAME;
  1528. BAIL_ON_FAILURE(hr);
  1529. }
  1530. _pPropertyCache->flushpropertycache();
  1531. hr = put_BSTR_Property( this, TEXT("governsID"), _pClassInfo->pszOID);
  1532. BAIL_ON_FAILURE(hr);
  1533. hr = put_LONG_Property( this, TEXT("objectClassCategory"),
  1534. _pClassInfo->dwType );
  1535. BAIL_ON_FAILURE(hr);
  1536. hr = MakeVariantFromPropStringTable( _pClassInfo->pOIDsMustContain,
  1537. _hSchema, &var );
  1538. BAIL_ON_FAILURE(hr);
  1539. hr = put_VARIANT_Property( this, TEXT("mustContain"), var );
  1540. BAIL_ON_FAILURE(hr);
  1541. if (fUmiCall) {
  1542. //
  1543. // Add as mandatoryProperties to cache.
  1544. //
  1545. hr = put_VARIANT_Property( this, TEXT("mandatoryProperties"), var );
  1546. BAIL_ON_FAILURE(hr);
  1547. hr = put_BSTR_Property( this, TEXT("Name"), this->_Name);
  1548. BAIL_ON_FAILURE(hr);
  1549. }
  1550. VariantClear( &var );
  1551. hr = MakeVariantFromPropStringTable( _pClassInfo->pOIDsMayContain,
  1552. _hSchema, &var );
  1553. BAIL_ON_FAILURE(hr);
  1554. hr = put_VARIANT_Property( this, TEXT("mayContain"), var );
  1555. BAIL_ON_FAILURE(hr);
  1556. if (fUmiCall) {
  1557. //
  1558. // Add to the cache as optionalProperties.
  1559. //
  1560. hr = put_VARIANT_Property( this, TEXT("optionalProperties"), var );
  1561. BAIL_ON_FAILURE(hr);
  1562. }
  1563. VariantClear( &var );
  1564. hr = MakeVariantFromStringArray( _pClassInfo->pOIDsSuperiorClasses, &var );
  1565. BAIL_ON_FAILURE(hr);
  1566. hr = put_VARIANT_Property( this, TEXT("subClassOf"), var );
  1567. BAIL_ON_FAILURE(hr);
  1568. VariantClear( &var );
  1569. hr = MakeVariantFromStringArray( _pClassInfo->pOIDsAuxClasses, &var );
  1570. BAIL_ON_FAILURE(hr);
  1571. hr = put_VARIANT_Property( this, TEXT("auxiliaryClass"), var );
  1572. BAIL_ON_FAILURE(hr);
  1573. VariantClear( &var );
  1574. if (_fNTDS) {
  1575. //
  1576. // Read the extra NTDS specific schema properties.
  1577. //
  1578. hr = GetNTDSSchemaInfo(TRUE);
  1579. BAIL_ON_FAILURE(hr);
  1580. }
  1581. _pPropertyCache->ClearAllPropertyFlags();
  1582. _pPropertyCache->setGetInfoFlag();
  1583. error:
  1584. if (pszLDAPServer) {
  1585. FreeADsStr(pszLDAPServer);
  1586. }
  1587. if (pszLDAPDn) {
  1588. FreeADsStr(pszLDAPDn);
  1589. }
  1590. VariantClear(&var);
  1591. RRETURN_EXP_IF_ERR(hr); // All current information are in _pClassInfo
  1592. }
  1593. //
  1594. // This routine is called only when the server is AD.
  1595. //
  1596. HRESULT
  1597. CLDAPClass::GetNTDSSchemaInfo(
  1598. BOOL fForce
  1599. )
  1600. {
  1601. HRESULT hr = S_OK;
  1602. LPTSTR aStrings[] = {
  1603. TEXT("cn"),
  1604. TEXT("displaySpecification"),
  1605. TEXT("schemaIDGUID"),
  1606. TEXT("possibleInferiors"),
  1607. TEXT("rDNAttid"),
  1608. TEXT("possSuperiors"),
  1609. TEXT("systemPossSuperiors"),
  1610. NULL
  1611. };
  1612. LDAPMessage *res = NULL;
  1613. if (_pszLDAPDn == NULL) {
  1614. //
  1615. // Need to get the dn for this object and also
  1616. // the attributes we are interested in.
  1617. //
  1618. hr = BuildSchemaLDAPPathAndGetAttribute(
  1619. _Parent,
  1620. _Name,
  1621. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  1622. _pClassInfo == NULL,
  1623. _Credentials,
  1624. aStrings,
  1625. &_pszLDAPServer,
  1626. &_pszLDAPDn,
  1627. &_ld,
  1628. &res
  1629. );
  1630. }
  1631. else {
  1632. //
  1633. // Looks like we just need the attributes in this case.
  1634. //
  1635. hr = LdapSearchS(
  1636. _ld,
  1637. _pszLDAPDn,
  1638. LDAP_SCOPE_BASE,
  1639. L"(objectClass=*)",
  1640. aStrings,
  1641. FALSE,
  1642. &res
  1643. );
  1644. }
  1645. BAIL_ON_FAILURE(hr);
  1646. //
  1647. // If we succeeded we should unmarshall properties into the cache.
  1648. //
  1649. hr = _pPropertyCache->LDAPUnMarshallProperties(
  1650. _pszLDAPServer,
  1651. _ld,
  1652. res,
  1653. fForce,
  1654. _Credentials
  1655. );
  1656. BAIL_ON_FAILURE(hr);
  1657. _pPropertyCache->setGetInfoFlag();
  1658. error:
  1659. if (res) {
  1660. LdapMsgFree(res);
  1661. }
  1662. RRETURN(hr);
  1663. }
  1664. //
  1665. // Helper function for Umi - defined in CCoreADsObject.
  1666. //
  1667. STDMETHODIMP
  1668. CLDAPClass::GetInfo(DWORD dwFlags)
  1669. {
  1670. HRESULT hr = S_OK;
  1671. if (dwFlags == GETINFO_FLAG_EXPLICIT) {
  1672. RRETURN(GetInfo());
  1673. }
  1674. else {
  1675. //
  1676. // Read NTDS info if this is not an implicit as needed call.
  1677. // That is this just a regular implicit GetInfo.
  1678. //
  1679. if (_fNTDS
  1680. && dwFlags != GETINFO_FLAG_IMPLICIT_AS_NEEDED
  1681. ) {
  1682. //
  1683. // Read the extra NTDS specific schema properties.
  1684. //
  1685. hr = GetNTDSSchemaInfo(FALSE);
  1686. }
  1687. }
  1688. RRETURN(hr);
  1689. }
  1690. STDMETHODIMP
  1691. CLDAPClass::Get(THIS_ BSTR bstrName, VARIANT FAR* pvProp)
  1692. {
  1693. HRESULT hr = S_OK;
  1694. DWORD dwSyntaxId;
  1695. LDAPOBJECTARRAY ldapSrcObjects;
  1696. DWORD dwStatus = 0;
  1697. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  1698. //
  1699. // For folks who know now what they do.
  1700. //
  1701. if (!pvProp) {
  1702. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1703. }
  1704. //
  1705. // retrieve data object from cache; if one exists
  1706. //
  1707. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  1708. hr = _pPropertyCache->unboundgetproperty(
  1709. bstrName,
  1710. &dwSyntaxId,
  1711. &dwStatus,
  1712. &ldapSrcObjects
  1713. );
  1714. // For backward compatibility
  1715. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  1716. hr = E_FAIL;
  1717. }
  1718. } else {
  1719. hr = _pPropertyCache->getproperty(
  1720. bstrName,
  1721. &dwSyntaxId,
  1722. &dwStatus,
  1723. &ldapSrcObjects
  1724. );
  1725. // For backward compatibility
  1726. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  1727. hr = E_ADS_PROPERTY_NOT_FOUND;
  1728. }
  1729. }
  1730. BAIL_ON_FAILURE(hr);
  1731. //
  1732. // translate the Ldap objects to variants
  1733. //
  1734. if ( ldapSrcObjects.dwCount == 1 ) {
  1735. hr = LdapTypeToVarTypeCopy(
  1736. _pszLDAPServer,
  1737. _Credentials,
  1738. ldapSrcObjects.pLdapObjects,
  1739. dwSyntaxId,
  1740. pvProp
  1741. );
  1742. } else {
  1743. hr = LdapTypeToVarTypeCopyConstruct(
  1744. _pszLDAPServer,
  1745. _Credentials,
  1746. ldapSrcObjects,
  1747. dwSyntaxId,
  1748. pvProp
  1749. );
  1750. }
  1751. BAIL_ON_FAILURE(hr);
  1752. error:
  1753. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  1754. RRETURN_EXP_IF_ERR(hr);
  1755. }
  1756. STDMETHODIMP
  1757. CLDAPClass::Put(THIS_ BSTR bstrName, VARIANT vProp)
  1758. {
  1759. HRESULT hr = S_OK;
  1760. DWORD dwSyntaxId = 0;
  1761. DWORD dwIndex = 0;
  1762. LDAPOBJECTARRAY ldapDestObjects;
  1763. DWORD dwNumValues = 0;
  1764. VARIANT * pVarArray = NULL;
  1765. VARIANT * pvProp = NULL;
  1766. VARIANT vDefProp;
  1767. VariantInit(&vDefProp);
  1768. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  1769. hr = SchemaGetSyntaxOfAttribute( _hSchema, bstrName, &dwSyntaxId );
  1770. if (FAILED(hr)) {
  1771. //
  1772. // Need to see if this is either mandatoryProperties or
  1773. // OptionalProperties that we special case for Umi Objects.
  1774. //
  1775. if (!_wcsicmp(L"mandatoryProperties", bstrName)
  1776. || !_wcsicmp(L"optionalProperties", bstrName)
  1777. ) {
  1778. dwSyntaxId = LDAPTYPE_CASEIGNORESTRING;
  1779. hr = S_OK;
  1780. }
  1781. }
  1782. BAIL_ON_FAILURE(hr);
  1783. if ( dwSyntaxId == LDAPTYPE_UNKNOWN )
  1784. {
  1785. hr = E_ADS_CANT_CONVERT_DATATYPE;
  1786. BAIL_ON_FAILURE(hr);
  1787. }
  1788. //
  1789. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1790. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1791. // what's inside.
  1792. //
  1793. pvProp = &vProp;
  1794. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  1795. pvProp = V_VARIANTREF(&vProp);
  1796. }
  1797. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  1798. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  1799. hr = ConvertSafeArrayToVariantArray(
  1800. *pvProp,
  1801. &pVarArray,
  1802. &dwNumValues
  1803. );
  1804. // returns E_FAIL if *pvProp is invalid
  1805. if (hr == E_FAIL)
  1806. hr = E_ADS_BAD_PARAMETER;
  1807. BAIL_ON_FAILURE(hr);
  1808. pvProp = pVarArray;
  1809. } else {
  1810. //
  1811. // If pvProp is a reference to a fundamental type, we
  1812. // have to derefernce it once.
  1813. //
  1814. if (V_ISBYREF(pvProp)) {
  1815. hr = VariantCopyInd(&vDefProp, pvProp);
  1816. BAIL_ON_FAILURE(hr);
  1817. pvProp = &vDefProp;
  1818. }
  1819. dwNumValues = 1;
  1820. }
  1821. #if 0
  1822. //
  1823. // check if this is a legal property for this object,
  1824. //
  1825. hr = ValidatePropertyinCache(
  1826. szLDAPTreeName,
  1827. _ADsClass,
  1828. bstrName,
  1829. &dwSyntaxId
  1830. );
  1831. BAIL_ON_FAILURE(hr);
  1832. #endif
  1833. //
  1834. // check if the variant maps to the syntax of this property
  1835. //
  1836. if ( dwNumValues > 0 )
  1837. {
  1838. hr = VarTypeToLdapTypeCopyConstruct(
  1839. _pszLDAPServer,
  1840. _Credentials,
  1841. dwSyntaxId,
  1842. pvProp,
  1843. dwNumValues,
  1844. &ldapDestObjects
  1845. );
  1846. BAIL_ON_FAILURE(hr);
  1847. }
  1848. //
  1849. // Find this property in the cache
  1850. //
  1851. hr = _pPropertyCache->findproperty(
  1852. bstrName,
  1853. &dwIndex
  1854. );
  1855. //
  1856. // If this property does not exist in the
  1857. // cache, add this property into the cache.
  1858. //
  1859. if (FAILED(hr)) {
  1860. hr = _pPropertyCache->addproperty( bstrName );
  1861. BAIL_ON_FAILURE(hr);
  1862. }
  1863. //
  1864. // Now update the property in the cache
  1865. //
  1866. hr = _pPropertyCache->putproperty(
  1867. bstrName,
  1868. PROPERTY_UPDATE,
  1869. dwSyntaxId,
  1870. ldapDestObjects
  1871. );
  1872. BAIL_ON_FAILURE(hr);
  1873. error:
  1874. VariantClear(&vDefProp);
  1875. LdapTypeFreeLdapObjects( &ldapDestObjects );
  1876. if (pVarArray) {
  1877. DWORD i = 0;
  1878. for (i = 0; i < dwNumValues; i++) {
  1879. VariantClear(pVarArray + i);
  1880. }
  1881. FreeADsMem(pVarArray);
  1882. }
  1883. RRETURN_EXP_IF_ERR(hr);
  1884. }
  1885. STDMETHODIMP
  1886. CLDAPClass::GetEx(THIS_ BSTR bstrName, VARIANT FAR* pvProp)
  1887. {
  1888. HRESULT hr = S_OK;
  1889. DWORD dwSyntaxId;
  1890. LDAPOBJECTARRAY ldapSrcObjects;
  1891. DWORD dwStatus = 0;
  1892. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  1893. //
  1894. // For those who know no not what they do
  1895. //
  1896. if (!pvProp) {
  1897. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1898. }
  1899. //
  1900. // retrieve data object from cache; if one exists
  1901. //
  1902. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  1903. hr = _pPropertyCache->unboundgetproperty(
  1904. bstrName,
  1905. &dwSyntaxId,
  1906. &dwStatus,
  1907. &ldapSrcObjects
  1908. );
  1909. // For backward compatibility
  1910. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  1911. hr = E_FAIL;
  1912. }
  1913. } else {
  1914. hr = _pPropertyCache->getproperty(
  1915. bstrName,
  1916. &dwSyntaxId,
  1917. &dwStatus,
  1918. &ldapSrcObjects
  1919. );
  1920. // For backward compatibility
  1921. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  1922. hr = E_ADS_PROPERTY_NOT_FOUND;
  1923. }
  1924. }
  1925. BAIL_ON_FAILURE(hr);
  1926. //
  1927. // translate the Ldap objects to variants
  1928. //
  1929. hr = LdapTypeToVarTypeCopyConstruct(
  1930. _pszLDAPServer,
  1931. _Credentials,
  1932. ldapSrcObjects,
  1933. dwSyntaxId,
  1934. pvProp
  1935. );
  1936. BAIL_ON_FAILURE(hr);
  1937. error:
  1938. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  1939. RRETURN_EXP_IF_ERR(hr);
  1940. }
  1941. STDMETHODIMP
  1942. CLDAPClass::PutEx(THIS_ long lnControlCode, BSTR bstrName, VARIANT vProp)
  1943. {
  1944. HRESULT hr = S_OK;
  1945. DWORD dwSyntaxId = 0;
  1946. DWORD dwFlags = 0;
  1947. DWORD dwIndex = 0;
  1948. LDAPOBJECTARRAY ldapDestObjects;
  1949. DWORD dwNumValues = 0;
  1950. VARIANT * pVarArray = NULL;
  1951. VARIANT * pvProp = NULL;
  1952. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  1953. switch (lnControlCode) {
  1954. case ADS_PROPERTY_CLEAR:
  1955. dwFlags = PROPERTY_DELETE;
  1956. break;
  1957. case ADS_PROPERTY_UPDATE:
  1958. dwFlags = PROPERTY_UPDATE;
  1959. break;
  1960. default:
  1961. RRETURN(hr = E_ADS_BAD_PARAMETER);
  1962. }
  1963. hr = SchemaGetSyntaxOfAttribute( _hSchema, bstrName, &dwSyntaxId );
  1964. BAIL_ON_FAILURE(hr);
  1965. if ( dwSyntaxId == LDAPTYPE_UNKNOWN )
  1966. {
  1967. hr = E_ADS_CANT_CONVERT_DATATYPE;
  1968. BAIL_ON_FAILURE(hr);
  1969. }
  1970. #if 0
  1971. //
  1972. // check if this is a legal property for this object,
  1973. //
  1974. hr = ValidatePropertyinCache(
  1975. szLDAPTreeName,
  1976. _ADsClass,
  1977. bstrName,
  1978. &dwSyntaxId
  1979. );
  1980. BAIL_ON_FAILURE(hr);
  1981. #endif
  1982. if ( dwFlags != PROPERTY_DELETE )
  1983. {
  1984. //
  1985. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1986. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1987. // what's inside.
  1988. //
  1989. pvProp = &vProp;
  1990. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  1991. pvProp = V_VARIANTREF(&vProp);
  1992. }
  1993. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  1994. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  1995. hr = ConvertSafeArrayToVariantArray(
  1996. *pvProp,
  1997. &pVarArray,
  1998. &dwNumValues
  1999. );
  2000. // returns E_FAIL if *pvProp is invalid
  2001. if (hr == E_FAIL)
  2002. hr = E_ADS_BAD_PARAMETER;
  2003. BAIL_ON_FAILURE(hr);
  2004. pvProp = pVarArray;
  2005. } else {
  2006. hr = E_FAIL;
  2007. BAIL_ON_FAILURE(hr);
  2008. }
  2009. //
  2010. // check if the variant maps to the syntax of this property
  2011. //
  2012. if ( dwNumValues > 0 )
  2013. {
  2014. hr = VarTypeToLdapTypeCopyConstruct(
  2015. _pszLDAPServer,
  2016. _Credentials,
  2017. dwSyntaxId,
  2018. pvProp,
  2019. dwNumValues,
  2020. &ldapDestObjects
  2021. );
  2022. BAIL_ON_FAILURE(hr);
  2023. }
  2024. }
  2025. //
  2026. // Find this property in the cache
  2027. //
  2028. hr = _pPropertyCache->findproperty(
  2029. bstrName,
  2030. &dwIndex
  2031. );
  2032. //
  2033. // If this property does not exist in the
  2034. // cache, add this property into the cache.
  2035. //
  2036. if (FAILED(hr)) {
  2037. hr = _pPropertyCache->addproperty( bstrName );
  2038. BAIL_ON_FAILURE(hr);
  2039. }
  2040. //
  2041. // Now update the property in the cache
  2042. //
  2043. hr = _pPropertyCache->putproperty(
  2044. bstrName,
  2045. PROPERTY_UPDATE,
  2046. dwSyntaxId,
  2047. ldapDestObjects
  2048. );
  2049. BAIL_ON_FAILURE(hr);
  2050. error:
  2051. LdapTypeFreeLdapObjects( &ldapDestObjects );
  2052. if (pVarArray) {
  2053. DWORD i = 0;
  2054. for (i = 0; i < dwNumValues; i++) {
  2055. VariantClear(pVarArray + i);
  2056. }
  2057. FreeADsMem(pVarArray);
  2058. }
  2059. RRETURN_EXP_IF_ERR(hr);
  2060. }
  2061. STDMETHODIMP
  2062. CLDAPClass::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
  2063. {
  2064. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  2065. }
  2066. /* IADsContainer methods */
  2067. /* IADsClass methods */
  2068. HRESULT
  2069. CLDAPClass::LoadInterfaceInfo(void)
  2070. {
  2071. HRESULT hr = S_OK;
  2072. BSTR bstrTmp = NULL;
  2073. if ( _pClassInfo ) {
  2074. GUID *pPrimaryInterfaceGUID = NULL;
  2075. GUID *pCLSID = NULL;
  2076. hr = SchemaGetPrimaryInterface( _hSchema,
  2077. _Name,
  2078. &pPrimaryInterfaceGUID,
  2079. &pCLSID );
  2080. if ( pPrimaryInterfaceGUID == NULL )
  2081. pPrimaryInterfaceGUID = (GUID *) &IID_IADs;
  2082. //
  2083. // Set the primary interface string
  2084. //
  2085. hr = StringFromCLSID((REFCLSID)*(pPrimaryInterfaceGUID),
  2086. &bstrTmp );
  2087. BAIL_ON_FAILURE(hr);
  2088. hr = ADsAllocString( bstrTmp,
  2089. &_bstrPrimaryInterface);
  2090. BAIL_ON_FAILURE(hr);
  2091. CoTaskMemFree(bstrTmp);
  2092. bstrTmp = NULL;
  2093. if ( pCLSID )
  2094. {
  2095. //
  2096. // Set the CLSID string
  2097. //
  2098. hr = StringFromCLSID( (REFCLSID) *(pCLSID),
  2099. &bstrTmp );
  2100. BAIL_ON_FAILURE(hr);
  2101. hr = ADsAllocString( bstrTmp,
  2102. &_bstrCLSID );
  2103. BAIL_ON_FAILURE(hr);
  2104. CoTaskMemFree(bstrTmp);
  2105. bstrTmp = NULL;
  2106. }
  2107. }
  2108. error:
  2109. if ( bstrTmp != NULL )
  2110. CoTaskMemFree(bstrTmp);
  2111. RRETURN(hr);
  2112. }
  2113. STDMETHODIMP
  2114. CLDAPClass::get_PrimaryInterface( THIS_ BSTR FAR *pbstrGUID )
  2115. {
  2116. HRESULT hr;
  2117. if ( !pbstrGUID )
  2118. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2119. if (!_fLoadedInterfaceInfo) {
  2120. hr = LoadInterfaceInfo();
  2121. BAIL_ON_FAILURE(hr);
  2122. _fLoadedInterfaceInfo = TRUE;
  2123. }
  2124. hr = ADsAllocString(
  2125. _bstrPrimaryInterface? _bstrPrimaryInterface : TEXT(""),
  2126. pbstrGUID );
  2127. error:
  2128. RRETURN_EXP_IF_ERR(hr);
  2129. }
  2130. STDMETHODIMP
  2131. CLDAPClass::get_CLSID( THIS_ BSTR FAR *pbstrCLSID )
  2132. {
  2133. HRESULT hr;
  2134. if ( !pbstrCLSID )
  2135. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2136. if (!_fLoadedInterfaceInfo) {
  2137. hr = LoadInterfaceInfo();
  2138. BAIL_ON_FAILURE(hr);
  2139. _fLoadedInterfaceInfo = TRUE;
  2140. }
  2141. hr = ADsAllocString( _bstrCLSID? _bstrCLSID: TEXT(""), pbstrCLSID );
  2142. error:
  2143. RRETURN_EXP_IF_ERR(hr);
  2144. }
  2145. STDMETHODIMP
  2146. CLDAPClass::put_CLSID( THIS_ BSTR bstrCLSID )
  2147. {
  2148. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  2149. }
  2150. STDMETHODIMP
  2151. CLDAPClass::get_OID( THIS_ BSTR FAR *retval )
  2152. {
  2153. if ( !retval )
  2154. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2155. HRESULT hr;
  2156. if ( _fNTDS )
  2157. {
  2158. GET_PROPERTY_BSTR( this, governsID );
  2159. }
  2160. else if ( _pClassInfo )
  2161. {
  2162. hr = ADsAllocString( _pClassInfo->pszOID?
  2163. _pClassInfo->pszOID : TEXT(""), retval );
  2164. RRETURN_EXP_IF_ERR(hr);
  2165. }
  2166. else
  2167. {
  2168. hr = ADsAllocString( TEXT(""), retval );
  2169. RRETURN_EXP_IF_ERR(hr);
  2170. }
  2171. }
  2172. STDMETHODIMP
  2173. CLDAPClass::put_OID( THIS_ BSTR bstrOID )
  2174. {
  2175. if ( !_fNTDS )
  2176. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  2177. HRESULT hr = put_BSTR_Property( this, TEXT("governsID"), bstrOID );
  2178. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  2179. {
  2180. _fNTDS = FALSE;
  2181. hr = E_NOTIMPL;
  2182. }
  2183. RRETURN_EXP_IF_ERR(hr);
  2184. }
  2185. STDMETHODIMP
  2186. CLDAPClass::get_Abstract( THIS_ VARIANT_BOOL FAR *pfAbstract )
  2187. {
  2188. if ( !pfAbstract )
  2189. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2190. HRESULT hr = S_OK;
  2191. long lClassType = CLASS_TYPE_STRUCTURAL; // by default
  2192. if ( _fNTDS )
  2193. {
  2194. hr = get_LONG_Property( this, TEXT("objectClassCategory"),
  2195. &lClassType );
  2196. BAIL_ON_FAILURE(hr);
  2197. }
  2198. else if ( _pClassInfo )
  2199. {
  2200. lClassType = _pClassInfo->dwType;
  2201. }
  2202. *pfAbstract = lClassType == CLASS_TYPE_ABSTRACT ?
  2203. VARIANT_TRUE : VARIANT_FALSE;
  2204. error:
  2205. RRETURN_EXP_IF_ERR(hr);
  2206. }
  2207. STDMETHODIMP
  2208. CLDAPClass::put_Abstract( THIS_ VARIANT_BOOL fAbstract )
  2209. {
  2210. if ( !_fNTDS )
  2211. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2212. long lClassType;
  2213. HRESULT hr = get_LONG_Property( this, TEXT("objectClassCategory"),
  2214. &lClassType );
  2215. if ( SUCCEEDED(hr))
  2216. {
  2217. if ( ( fAbstract && lClassType == CLASS_TYPE_ABSTRACT )
  2218. || ( !fAbstract && lClassType != CLASS_TYPE_ABSTRACT )
  2219. )
  2220. {
  2221. RRETURN(S_OK); // Nothing to set
  2222. }
  2223. }
  2224. hr = put_LONG_Property( (IADs *) this,
  2225. TEXT("objectClassCategory"),
  2226. fAbstract? CLASS_TYPE_ABSTRACT
  2227. : CLASS_TYPE_STRUCTURAL );
  2228. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  2229. {
  2230. _fNTDS = FALSE;
  2231. hr = E_NOTIMPL;
  2232. }
  2233. RRETURN_EXP_IF_ERR(hr);
  2234. }
  2235. STDMETHODIMP
  2236. CLDAPClass::get_Auxiliary( THIS_ VARIANT_BOOL FAR *pfAuxiliary )
  2237. {
  2238. if ( !pfAuxiliary )
  2239. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2240. HRESULT hr = S_OK;
  2241. long lClassType = CLASS_TYPE_STRUCTURAL; // by default
  2242. if ( _fNTDS )
  2243. {
  2244. hr = get_LONG_Property( this, TEXT("objectClassCategory"),
  2245. &lClassType );
  2246. BAIL_ON_FAILURE(hr);
  2247. }
  2248. else if ( _pClassInfo )
  2249. {
  2250. lClassType = _pClassInfo->dwType;
  2251. }
  2252. *pfAuxiliary = lClassType == CLASS_TYPE_AUXILIARY ?
  2253. VARIANT_TRUE : VARIANT_FALSE;
  2254. error:
  2255. RRETURN_EXP_IF_ERR(hr);
  2256. }
  2257. STDMETHODIMP
  2258. CLDAPClass::put_Auxiliary( THIS_ VARIANT_BOOL fAuxiliary )
  2259. {
  2260. if ( !_fNTDS )
  2261. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2262. long lClassType = CLASS_TYPE_STRUCTURAL;
  2263. HRESULT hr = get_LONG_Property( this, TEXT("objectClassCategory"),
  2264. &lClassType );
  2265. if ( SUCCEEDED(hr))
  2266. {
  2267. if ( ( fAuxiliary && lClassType == CLASS_TYPE_AUXILIARY )
  2268. || ( !fAuxiliary && lClassType != CLASS_TYPE_AUXILIARY )
  2269. )
  2270. {
  2271. RRETURN(S_OK); // Nothing to set
  2272. }
  2273. }
  2274. hr = put_LONG_Property( (IADs *) this,
  2275. TEXT("objectClassCategory"),
  2276. fAuxiliary? CLASS_TYPE_AUXILIARY
  2277. : CLASS_TYPE_STRUCTURAL );
  2278. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  2279. {
  2280. _fNTDS = FALSE;
  2281. hr = E_NOTIMPL;
  2282. }
  2283. RRETURN_EXP_IF_ERR(hr);
  2284. }
  2285. STDMETHODIMP
  2286. CLDAPClass::get_MandatoryProperties( THIS_ VARIANT FAR *retval )
  2287. {
  2288. HRESULT hr = S_OK;
  2289. if ( !retval )
  2290. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2291. VariantInit( retval );
  2292. if ( _fNTDS )
  2293. {
  2294. GET_PROPERTY_VARIANT( this, mustContain );
  2295. }
  2296. else if ( _pClassInfo )
  2297. {
  2298. hr = MakeVariantFromPropStringTable( _pClassInfo->pOIDsMustContain,
  2299. _hSchema,
  2300. retval );
  2301. }
  2302. else
  2303. {
  2304. hr = MakeVariantFromStringArray( NULL,
  2305. retval );
  2306. }
  2307. RRETURN_EXP_IF_ERR(hr);
  2308. }
  2309. STDMETHODIMP
  2310. CLDAPClass::put_MandatoryProperties( THIS_ VARIANT vMandatoryProperties )
  2311. {
  2312. if ( !_fNTDS )
  2313. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2314. HRESULT hr = put_VARIANT_Property( this, TEXT("mustContain"),
  2315. vMandatoryProperties );
  2316. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  2317. {
  2318. _fNTDS = FALSE;
  2319. hr = E_NOTIMPL;
  2320. }
  2321. RRETURN_EXP_IF_ERR(hr);
  2322. }
  2323. STDMETHODIMP
  2324. CLDAPClass::get_OptionalProperties( THIS_ VARIANT FAR *retval )
  2325. {
  2326. HRESULT hr = S_OK;
  2327. if ( !retval )
  2328. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2329. VariantInit( retval );
  2330. if ( _fNTDS )
  2331. {
  2332. GET_PROPERTY_VARIANT( this, mayContain );
  2333. }
  2334. else if ( _pClassInfo )
  2335. {
  2336. hr = MakeVariantFromPropStringTable( _pClassInfo->pOIDsMayContain,
  2337. _hSchema,
  2338. retval );
  2339. }
  2340. else
  2341. {
  2342. hr = MakeVariantFromStringArray( NULL,
  2343. retval );
  2344. }
  2345. RRETURN_EXP_IF_ERR(hr);
  2346. }
  2347. STDMETHODIMP
  2348. CLDAPClass::put_OptionalProperties( THIS_ VARIANT vOptionalProperties )
  2349. {
  2350. if ( !_fNTDS )
  2351. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2352. HRESULT hr = put_VARIANT_Property( this, TEXT("mayContain"),
  2353. vOptionalProperties );
  2354. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  2355. {
  2356. _fNTDS = FALSE;
  2357. hr = E_NOTIMPL;
  2358. }
  2359. RRETURN_EXP_IF_ERR(hr);
  2360. }
  2361. STDMETHODIMP
  2362. CLDAPClass::get_NamingProperties( THIS_ VARIANT FAR *pvNamingProperties )
  2363. {
  2364. HRESULT hr = S_OK;
  2365. if ( !pvNamingProperties )
  2366. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2367. if ( !_fNTDS )
  2368. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2369. VariantInit( pvNamingProperties );
  2370. hr = get_VARIANT_Property( this, TEXT("rDNAttId"), pvNamingProperties );
  2371. if ( SUCCEEDED(hr) )
  2372. RRETURN(hr);
  2373. hr = get_NTDSProp_Helper( TEXT("rDNAttId"), pvNamingProperties );
  2374. RRETURN_EXP_IF_ERR(hr);
  2375. }
  2376. STDMETHODIMP
  2377. CLDAPClass::put_NamingProperties( THIS_ VARIANT vNamingProperties )
  2378. {
  2379. if ( !_fNTDS )
  2380. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2381. HRESULT hr = put_VARIANT_Property( this, TEXT("rDNAttId"),
  2382. vNamingProperties );
  2383. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  2384. {
  2385. _fNTDS = FALSE;
  2386. hr = E_NOTIMPL;
  2387. }
  2388. RRETURN_EXP_IF_ERR(hr);
  2389. }
  2390. STDMETHODIMP
  2391. CLDAPClass::get_DerivedFrom( THIS_ VARIANT FAR *retval )
  2392. {
  2393. HRESULT hr = S_OK;
  2394. if ( !retval )
  2395. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2396. VariantInit( retval );
  2397. if ( _fNTDS )
  2398. {
  2399. GET_PROPERTY_VARIANT( this, subClassOf );
  2400. }
  2401. else if ( _pClassInfo )
  2402. {
  2403. hr = MakeVariantFromStringArray( _pClassInfo->pOIDsSuperiorClasses,
  2404. retval );
  2405. }
  2406. else
  2407. {
  2408. hr = MakeVariantFromStringArray( NULL,
  2409. retval );
  2410. }
  2411. RRETURN_EXP_IF_ERR(hr);
  2412. }
  2413. STDMETHODIMP
  2414. CLDAPClass::put_DerivedFrom( THIS_ VARIANT vDerivedFrom )
  2415. {
  2416. if ( !_fNTDS )
  2417. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2418. HRESULT hr = put_VARIANT_Property( this, TEXT("subClassOf"),
  2419. vDerivedFrom );
  2420. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  2421. {
  2422. _fNTDS = FALSE;
  2423. hr = E_NOTIMPL;
  2424. }
  2425. RRETURN_EXP_IF_ERR(hr);
  2426. }
  2427. STDMETHODIMP
  2428. CLDAPClass::get_AuxDerivedFrom( THIS_ VARIANT FAR *retval )
  2429. {
  2430. HRESULT hr = S_OK;
  2431. if ( !retval )
  2432. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2433. VariantInit( retval );
  2434. if ( _fNTDS )
  2435. {
  2436. GET_PROPERTY_VARIANT( this, auxiliaryClass );
  2437. }
  2438. else if ( _pClassInfo )
  2439. {
  2440. hr = MakeVariantFromStringArray( _pClassInfo->pOIDsAuxClasses,
  2441. retval );
  2442. }
  2443. else
  2444. {
  2445. hr = MakeVariantFromStringArray( NULL,
  2446. retval );
  2447. }
  2448. RRETURN_EXP_IF_ERR(hr);
  2449. }
  2450. STDMETHODIMP
  2451. CLDAPClass::put_AuxDerivedFrom( THIS_ VARIANT vAuxDerivedFrom )
  2452. {
  2453. if ( !_fNTDS )
  2454. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2455. HRESULT hr = put_VARIANT_Property( this, TEXT("auxiliaryClass"),
  2456. vAuxDerivedFrom );
  2457. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  2458. {
  2459. _fNTDS = FALSE;
  2460. hr = E_NOTIMPL;
  2461. }
  2462. RRETURN_EXP_IF_ERR(hr);
  2463. }
  2464. STDMETHODIMP
  2465. CLDAPClass::get_PossibleSuperiors( THIS_ VARIANT FAR *pvPossSuperiors)
  2466. {
  2467. HRESULT hr = S_OK;
  2468. VARIANT vSysPossSuperiors;
  2469. DWORD dwSyntaxId;
  2470. DWORD dwStatus = 0;
  2471. // Boolean values used to indicate if the values exist
  2472. BOOL fpossSuperiors = FALSE;
  2473. BOOL fsysPossSuperiors = FALSE;
  2474. // Used in case we need a union of the values
  2475. LDAPOBJECTARRAY ldapSrcObjects1;
  2476. LDAPOBJECTARRAY ldapSrcObjects2;
  2477. LDAPOBJECTARRAY_INIT(ldapSrcObjects1);
  2478. LDAPOBJECTARRAY_INIT(ldapSrcObjects2);
  2479. VariantInit(&vSysPossSuperiors);
  2480. if ( !pvPossSuperiors )
  2481. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2482. if ( !_fNTDS )
  2483. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2484. VariantInit( pvPossSuperiors );
  2485. hr = get_VARIANT_Property( this, TEXT("possSuperiors"), pvPossSuperiors );
  2486. if ( SUCCEEDED(hr) ){
  2487. fpossSuperiors = TRUE;
  2488. }
  2489. hr = get_VARIANT_Property(
  2490. this, TEXT("systemPossSuperiors"), &vSysPossSuperiors
  2491. );
  2492. if (SUCCEEDED(hr)) {
  2493. fsysPossSuperiors = TRUE;
  2494. }
  2495. if (!fpossSuperiors) {
  2496. hr = get_NTDSProp_Helper( TEXT("possSuperiors"), pvPossSuperiors );
  2497. if (SUCCEEDED(hr)) {
  2498. fpossSuperiors = TRUE;
  2499. }
  2500. }
  2501. if (!fsysPossSuperiors) {
  2502. hr = get_NTDSProp_Helper(
  2503. TEXT("systemPossSuperiors"), &vSysPossSuperiors
  2504. );
  2505. if (SUCCEEDED(hr)) {
  2506. fsysPossSuperiors = TRUE;
  2507. }
  2508. }
  2509. // Now if both are true, we need to do a union
  2510. if (fpossSuperiors && fsysPossSuperiors) {
  2511. // need to do the union
  2512. // it is easier for me to handle strings in the ldap format
  2513. // than to handle them as variants as there are helpers available
  2514. // for that already
  2515. hr = _pPropertyCache->unboundgetproperty(
  2516. L"possSuperiors",
  2517. &dwSyntaxId,
  2518. &dwStatus,
  2519. &ldapSrcObjects1
  2520. );
  2521. // No compatibility -- below it resets hr
  2522. if (hr == E_FAIL) {
  2523. hr = S_OK;
  2524. }
  2525. BAIL_ON_FAILURE(hr);
  2526. hr = _pPropertyCache->unboundgetproperty(
  2527. L"systemPossSuperiors",
  2528. &dwSyntaxId,
  2529. &dwStatus,
  2530. &ldapSrcObjects2
  2531. );
  2532. // No compatibility -- below it resets hr
  2533. if (hr == E_FAIL) {
  2534. hr = S_OK;
  2535. }
  2536. BAIL_ON_FAILURE(hr);
  2537. // Clear them as we no longer need the data here
  2538. VariantClear(pvPossSuperiors);
  2539. VariantClear(&vSysPossSuperiors);
  2540. hr = makeUnionVariantFromLdapObjects(
  2541. ldapSrcObjects1,
  2542. ldapSrcObjects2,
  2543. pvPossSuperiors
  2544. );
  2545. BAIL_ON_FAILURE(hr);
  2546. }
  2547. else if (fpossSuperiors || fsysPossSuperiors) {
  2548. // return the appropriate value in the variant
  2549. if (fsysPossSuperiors) {
  2550. hr = VariantCopy(pvPossSuperiors, &vSysPossSuperiors);
  2551. VariantClear(&vSysPossSuperiors);
  2552. BAIL_ON_FAILURE(hr);
  2553. }
  2554. }
  2555. error:
  2556. LdapTypeFreeLdapObjects(&ldapSrcObjects1);
  2557. LdapTypeFreeLdapObjects(&ldapSrcObjects2);
  2558. // this will make sure we handle fall through correctly
  2559. if (SUCCEEDED(hr)) {
  2560. RRETURN(hr);
  2561. }
  2562. VariantClear(pvPossSuperiors);
  2563. VariantClear(&vSysPossSuperiors);
  2564. RRETURN_EXP_IF_ERR(hr);
  2565. }
  2566. STDMETHODIMP
  2567. CLDAPClass::put_PossibleSuperiors( THIS_ VARIANT vPossSuperiors)
  2568. {
  2569. if ( !_fNTDS )
  2570. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2571. HRESULT hr = put_VARIANT_Property( this, TEXT("possSuperiors"),
  2572. vPossSuperiors);
  2573. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  2574. {
  2575. _fNTDS = FALSE;
  2576. hr = E_NOTIMPL;
  2577. }
  2578. RRETURN_EXP_IF_ERR(hr);
  2579. }
  2580. STDMETHODIMP
  2581. CLDAPClass::get_Containment( THIS_ VARIANT *pvContainment )
  2582. {
  2583. HRESULT hr = S_OK;
  2584. LPTSTR *aValues = NULL;
  2585. if ( !pvContainment )
  2586. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2587. if ( !_fNTDS )
  2588. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2589. VariantInit( pvContainment );
  2590. //
  2591. // This call will fetch possibleInferiors if necessary using
  2592. // an implicit GetInfo.
  2593. //
  2594. hr = GetEx(L"possibleInferiors", pvContainment);
  2595. if (FAILED(hr) &&
  2596. (hr == E_ADS_PROPERTY_NOT_FOUND)
  2597. ) {
  2598. //
  2599. // In this case we need to return an empty array
  2600. //
  2601. hr = MakeVariantFromStringArray(
  2602. aValues,
  2603. pvContainment
  2604. );
  2605. }
  2606. RRETURN_EXP_IF_ERR(hr);
  2607. }
  2608. STDMETHODIMP
  2609. CLDAPClass::put_Containment( THIS_ VARIANT vContainment)
  2610. {
  2611. if ( !_fNTDS )
  2612. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2613. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  2614. }
  2615. STDMETHODIMP
  2616. CLDAPClass::get_Container( THIS_ VARIANT_BOOL FAR *pfContainer )
  2617. {
  2618. HRESULT hr = S_OK;
  2619. VARIANT vVar;
  2620. if (!pfContainer) {
  2621. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2622. }
  2623. *pfContainer = VARIANT_FALSE;
  2624. if ( !_fNTDS )
  2625. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2626. VariantInit(&vVar);
  2627. //
  2628. // We now cache possibleInferiors as part of a GetInfo call.
  2629. //
  2630. hr = GetEx(L"possibleInferiors", &vVar);
  2631. if (SUCCEEDED(hr)) {
  2632. //
  2633. // Need to see if there were any values and not just NULL.
  2634. //
  2635. if (V_VT(&vVar) != (VT_VARIANT | VT_ARRAY)) {
  2636. //
  2637. // Not the expected result has
  2638. //
  2639. *pfContainer = VARIANT_FALSE;
  2640. }
  2641. else {
  2642. //
  2643. // Need to see how many elements are there.
  2644. //
  2645. LONG lnLBound = 0, lnUBound = 0;
  2646. hr = SafeArrayGetUBound(
  2647. V_ARRAY(&vVar),
  2648. 1,
  2649. &lnUBound
  2650. );
  2651. if (SUCCEEDED(hr)) {
  2652. hr = SafeArrayGetLBound(
  2653. V_ARRAY(&vVar),
  2654. 1,
  2655. &lnLBound
  2656. );
  2657. if (SUCCEEDED(hr)) {
  2658. //
  2659. // Check the length and make sure it is not 0 vals.
  2660. //
  2661. if ((lnUBound - lnLBound) + 1) {
  2662. *pfContainer = VARIANT_TRUE;
  2663. }
  2664. }
  2665. else {
  2666. //
  2667. // Default to not container in this case
  2668. //
  2669. *pfContainer = VARIANT_FALSE;
  2670. }
  2671. }
  2672. hr = S_OK;
  2673. }
  2674. // we need to release the memory in vVar
  2675. VariantClear(&vVar);
  2676. }
  2677. else if (FAILED(hr)
  2678. && (hr == E_ADS_PROPERTY_NOT_FOUND)
  2679. ) {
  2680. *pfContainer = VARIANT_FALSE;
  2681. hr = S_OK;
  2682. }
  2683. //
  2684. // Anything other than these and we should return the
  2685. // appropriate hr back.
  2686. //
  2687. RRETURN_EXP_IF_ERR(hr);
  2688. }
  2689. STDMETHODIMP
  2690. CLDAPClass::put_Container( THIS_ VARIANT_BOOL fContainer )
  2691. {
  2692. if ( !_fNTDS )
  2693. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2694. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  2695. }
  2696. STDMETHODIMP
  2697. CLDAPClass::get_HelpFileName( THIS_ BSTR FAR *pbstrHelpFileName )
  2698. {
  2699. if ( !pbstrHelpFileName )
  2700. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2701. HRESULT hr;
  2702. hr = ADsAllocString( _bstrHelpFileName?
  2703. _bstrHelpFileName: TEXT(""),
  2704. pbstrHelpFileName );
  2705. RRETURN_EXP_IF_ERR(hr);
  2706. }
  2707. STDMETHODIMP
  2708. CLDAPClass::put_HelpFileName( THIS_ BSTR bstrHelpFile )
  2709. {
  2710. if ( !_fNTDS )
  2711. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2712. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  2713. #if 0
  2714. RRETURN( ADsReAllocString( &_bstrHelpFileName,
  2715. bstrHelpFile? bstrHelpFile: TEXT("") ));
  2716. #endif
  2717. }
  2718. STDMETHODIMP
  2719. CLDAPClass::get_HelpFileContext( THIS_ long FAR *plHelpContext )
  2720. {
  2721. if ( !plHelpContext )
  2722. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2723. *plHelpContext = _lHelpFileContext;
  2724. RRETURN(S_OK);
  2725. }
  2726. STDMETHODIMP
  2727. CLDAPClass::put_HelpFileContext( THIS_ long lHelpContext )
  2728. {
  2729. if ( !_fNTDS )
  2730. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  2731. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  2732. #if 0
  2733. _lHelpFileContext = lHelpContext;
  2734. RRETURN(S_OK);
  2735. #endif
  2736. }
  2737. STDMETHODIMP
  2738. CLDAPClass::Qualifiers(THIS_ IADsCollection FAR* FAR* ppQualifiers)
  2739. {
  2740. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  2741. }
  2742. HRESULT
  2743. CLDAPClass::AllocateClassObject(
  2744. CCredentials& Credentials,
  2745. CLDAPClass FAR * FAR * ppClass
  2746. )
  2747. {
  2748. CLDAPClass FAR *pClass = NULL;
  2749. CAggregatorDispMgr FAR *pDispMgr = NULL;
  2750. CPropertyCache FAR *pPropertyCache = NULL;
  2751. HRESULT hr = S_OK;
  2752. pClass = new CLDAPClass();
  2753. if ( pClass == NULL )
  2754. hr = E_OUTOFMEMORY;
  2755. BAIL_ON_FAILURE(hr);
  2756. pDispMgr = new CAggregatorDispMgr(Credentials);
  2757. if ( pDispMgr == NULL )
  2758. hr = E_OUTOFMEMORY;
  2759. BAIL_ON_FAILURE(hr);
  2760. hr = pDispMgr->LoadTypeInfoEntry(
  2761. LIBID_ADs,
  2762. IID_IADs,
  2763. (IADs *) pClass,
  2764. DISPID_REGULAR );
  2765. BAIL_ON_FAILURE(hr);
  2766. hr = pDispMgr->LoadTypeInfoEntry(
  2767. LIBID_ADs,
  2768. IID_IADsClass,
  2769. (IADsClass *) pClass,
  2770. DISPID_REGULAR );
  2771. BAIL_ON_FAILURE(hr);
  2772. hr = CPropertyCache::createpropertycache(
  2773. (CCoreADsObject FAR *) pClass,
  2774. (IGetAttributeSyntax *) pClass,
  2775. &pPropertyCache
  2776. );
  2777. BAIL_ON_FAILURE(hr);
  2778. pDispMgr->RegisterPropertyCache(pPropertyCache);
  2779. pClass->_Credentials = Credentials;
  2780. pClass->_pDispMgr = pDispMgr;
  2781. pClass->_pPropertyCache = pPropertyCache;
  2782. *ppClass = pClass;
  2783. RRETURN(hr);
  2784. error:
  2785. delete pDispMgr;
  2786. delete pClass;
  2787. RRETURN_EXP_IF_ERR(hr);
  2788. }
  2789. HRESULT CLDAPClass::FindModifications(
  2790. int *pOIDs,
  2791. DWORD nNumOfOids,
  2792. LPTSTR pszPropName,
  2793. LDAPModW ***aMods,
  2794. DWORD *pdwNumOfMods
  2795. )
  2796. {
  2797. HRESULT hr = S_OK;
  2798. int *pOIDsOld = _tcsicmp(pszPropName, TEXT("mustContain")) == 0
  2799. ? _pClassInfo->pOIDsMustContain
  2800. : _pClassInfo->pOIDsMayContain;
  2801. DWORD i = 0;
  2802. DWORD j = 0;
  2803. DWORD k = 0;
  2804. BOOL fReadProperty = FALSE;
  2805. int *pOIDsCurrent = NULL;
  2806. DWORD nNumOfOidsCurrent = 0;
  2807. BOOL fFound = FALSE;
  2808. LPTSTR *aValuesAdd = NULL;
  2809. DWORD nValuesAdd = 0;
  2810. DWORD nValuesAddTotal = 10;
  2811. LPTSTR *aValuesRemove = NULL;
  2812. DWORD nValuesRemove = 0;
  2813. DWORD nValuesRemoveTotal = 10;
  2814. DWORD nIndex = 0;
  2815. LDAPMessage *res = NULL;
  2816. LDAPMessage *e = NULL;
  2817. LPTSTR aStrings[] = {
  2818. TEXT("cn"),
  2819. pszPropName,
  2820. NULL
  2821. };
  2822. aValuesAdd = (LPTSTR *) AllocADsMem(sizeof(LPTSTR) * nValuesAddTotal );
  2823. if ( aValuesAdd == NULL )
  2824. {
  2825. hr = E_OUTOFMEMORY;
  2826. BAIL_ON_FAILURE(hr);
  2827. }
  2828. aValuesRemove = (LPTSTR *) AllocADsMem(sizeof(LPTSTR) * nValuesRemoveTotal);
  2829. if ( aValuesRemove == NULL )
  2830. {
  2831. hr = E_OUTOFMEMORY;
  2832. BAIL_ON_FAILURE(hr);
  2833. }
  2834. //
  2835. // We need to find the differences between the properties that needs to be
  2836. // set and the properties that is currently on the server.
  2837. //
  2838. while ((pOIDs[j] != -1) || (pOIDsOld[k] != -1))
  2839. {
  2840. if ( pOIDs[j] == pOIDsOld[k] )
  2841. {
  2842. // No changes here
  2843. j++; k++;
  2844. }
  2845. else if ( ( pOIDsOld[k] == -1 )
  2846. || ( ( pOIDs[j] != -1 ) && ( pOIDs[j] < pOIDsOld[k] ))
  2847. )
  2848. {
  2849. //
  2850. // A new property has been added.
  2851. //
  2852. if ( nValuesAdd == nValuesAddTotal )
  2853. {
  2854. aValuesAdd = (LPTSTR *) ReallocADsMem( aValuesAdd,
  2855. sizeof(LPTSTR) * nValuesAddTotal,
  2856. sizeof(LPTSTR) * nValuesAddTotal * 2 );
  2857. if ( aValuesAdd == NULL )
  2858. {
  2859. hr = E_OUTOFMEMORY;
  2860. BAIL_ON_FAILURE(hr);
  2861. }
  2862. nValuesAddTotal *= 2;
  2863. }
  2864. nIndex = (((SCHEMAINFO *)_hSchema)->aPropertiesSearchTable[pOIDs[j]]).nIndex;
  2865. aValuesAdd[nValuesAdd++] =
  2866. (((SCHEMAINFO *)_hSchema)->aProperties[nIndex]).pszPropertyName;
  2867. j++;
  2868. }
  2869. else // ( pOIDs[j] == -1 || pOIDs[j] > pOIDsOld[k] )
  2870. {
  2871. // Some property has been removed, we need to read the current class
  2872. // set of "mayContain" or "mustContain" to make sure we
  2873. // aren't removing any "systemMustContain" or "systemMayContain"
  2874. // and we are not trying to remove any parent classes
  2875. // may/mustContain
  2876. if ( !fReadProperty )
  2877. {
  2878. LPTSTR *aValues = NULL;
  2879. int nCount = 0;
  2880. if ( _pszLDAPDn == NULL )
  2881. {
  2882. hr = BuildSchemaLDAPPathAndGetAttribute(
  2883. _Parent,
  2884. _Name,
  2885. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  2886. _pClassInfo == NULL,
  2887. _Credentials,
  2888. aStrings,
  2889. &_pszLDAPServer,
  2890. &_pszLDAPDn,
  2891. &_ld,
  2892. &res
  2893. );
  2894. BAIL_ON_FAILURE(hr);
  2895. hr = LdapFirstEntry(
  2896. _ld,
  2897. res,
  2898. &e
  2899. );
  2900. BAIL_ON_FAILURE(hr);
  2901. hr = LdapGetValues(
  2902. _ld,
  2903. e,
  2904. pszPropName,
  2905. &aValues,
  2906. &nCount
  2907. );
  2908. }
  2909. else
  2910. {
  2911. hr = LdapReadAttribute(
  2912. _pszLDAPServer,
  2913. _pszLDAPDn,
  2914. pszPropName,
  2915. &aValues,
  2916. &nCount,
  2917. _Credentials,
  2918. _dwPort
  2919. );
  2920. }
  2921. if ( hr == HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) )
  2922. {
  2923. hr = S_OK;
  2924. }
  2925. BAIL_ON_FAILURE(hr);
  2926. fReadProperty = TRUE;
  2927. if ( nCount > 0 )
  2928. {
  2929. hr = MakePropArrayFromStringArray( aValues,
  2930. nCount,
  2931. (SCHEMAINFO *) _hSchema,
  2932. &pOIDsCurrent,
  2933. &nNumOfOidsCurrent );
  2934. LdapValueFree( aValues );
  2935. BAIL_ON_FAILURE(hr);
  2936. }
  2937. }
  2938. //
  2939. // See if we can find the property that we want to remove from.
  2940. // We don't need to reset i since both arrays are sorted.
  2941. //
  2942. for ( fFound = FALSE; i < nNumOfOidsCurrent; i++ )
  2943. {
  2944. if ( pOIDsOld[k] == pOIDsCurrent[i] )
  2945. {
  2946. fFound = TRUE;
  2947. break;
  2948. }
  2949. else if ( pOIDsOld[k] < pOIDsCurrent[i] )
  2950. {
  2951. // Both arrays are sorted, so we can break here
  2952. break;
  2953. }
  2954. }
  2955. if ( nNumOfOidsCurrent == 0 || !fFound )
  2956. {
  2957. int err = NO_ERROR;
  2958. // This property is not in "mustContain" or "mayContain",
  2959. // so nothing can be removed
  2960. hr = E_ADS_SCHEMA_VIOLATION;
  2961. BAIL_ON_FAILURE(hr);
  2962. }
  2963. //
  2964. // Modify the request to remove the property here
  2965. //
  2966. if ( nValuesRemove == nValuesRemoveTotal )
  2967. {
  2968. aValuesRemove = (LPTSTR *) ReallocADsMem( aValuesRemove,
  2969. sizeof(LPTSTR) * nValuesRemoveTotal,
  2970. sizeof(LPTSTR) * nValuesRemoveTotal * 2 );
  2971. if ( aValuesRemove == NULL )
  2972. {
  2973. hr = E_OUTOFMEMORY;
  2974. BAIL_ON_FAILURE(hr);
  2975. }
  2976. nValuesRemoveTotal *= 2;
  2977. }
  2978. nIndex = (((SCHEMAINFO *)_hSchema)->aPropertiesSearchTable[pOIDsOld[k]]).nIndex;
  2979. aValuesRemove[nValuesRemove++] =
  2980. (((SCHEMAINFO *)_hSchema)->aProperties[nIndex]).pszPropertyName;
  2981. k++;
  2982. }
  2983. }
  2984. if ( nValuesAdd == 0 )
  2985. {
  2986. FreeADsMem( aValuesAdd );
  2987. aValuesAdd = NULL;
  2988. }
  2989. if ( nValuesRemove == 0 )
  2990. {
  2991. FreeADsMem( aValuesRemove );
  2992. aValuesRemove = NULL;
  2993. }
  2994. if ( aValuesAdd || aValuesRemove )
  2995. {
  2996. hr = AddModifyRequest(
  2997. aMods,
  2998. pdwNumOfMods,
  2999. pszPropName,
  3000. aValuesAdd,
  3001. aValuesRemove );
  3002. }
  3003. error:
  3004. if ( pOIDsCurrent )
  3005. FreeADsMem( pOIDsCurrent );
  3006. if (res)
  3007. LdapMsgFree(res);
  3008. if ( FAILED(hr))
  3009. {
  3010. if ( aValuesAdd )
  3011. FreeADsMem( aValuesAdd );
  3012. if ( aValuesRemove )
  3013. FreeADsMem( aValuesRemove );
  3014. }
  3015. RRETURN_EXP_IF_ERR(hr);
  3016. }
  3017. HRESULT CLDAPClass::AddModifyRequest(
  3018. LDAPModW ***aMods,
  3019. DWORD *pdwNumOfMods,
  3020. LPTSTR pszPropName,
  3021. LPTSTR *aValuesAdd,
  3022. LPTSTR *aValuesRemove
  3023. )
  3024. {
  3025. HRESULT hr = S_OK;
  3026. LDAPModW *aModsBuffer = NULL;
  3027. DWORD j = 0;
  3028. DWORD nCount = 0;
  3029. if ( aValuesAdd != NULL )
  3030. nCount++;
  3031. if ( aValuesRemove != NULL )
  3032. nCount++;
  3033. if ( nCount == 0 )
  3034. RRETURN(S_OK);
  3035. if ( *aMods == NULL )
  3036. {
  3037. *aMods = (LDAPModW **) AllocADsMem( (nCount + 1) * sizeof(LDAPModW *));
  3038. if ( *aMods == NULL )
  3039. {
  3040. hr = E_OUTOFMEMORY;
  3041. BAIL_ON_FAILURE(hr);
  3042. }
  3043. aModsBuffer = (LDAPModW *) AllocADsMem( nCount * sizeof(LDAPModW));
  3044. if ( aModsBuffer == NULL )
  3045. {
  3046. FreeADsMem( *aMods );
  3047. *aMods = NULL;
  3048. hr = E_OUTOFMEMORY;
  3049. BAIL_ON_FAILURE(hr);
  3050. }
  3051. }
  3052. else
  3053. {
  3054. LDAPModW **aModsTemp = NULL;
  3055. aModsTemp = (LDAPModW **) AllocADsMem(
  3056. (*pdwNumOfMods + nCount + 1) * sizeof(LDAPModW *));
  3057. if ( aModsTemp == NULL )
  3058. {
  3059. hr = E_OUTOFMEMORY;
  3060. BAIL_ON_FAILURE(hr);
  3061. }
  3062. aModsBuffer = (LDAPModW *) AllocADsMem(
  3063. (*pdwNumOfMods + nCount) * sizeof(LDAPModW));
  3064. if ( aModsBuffer == NULL )
  3065. {
  3066. FreeADsMem( aModsTemp );
  3067. hr = E_OUTOFMEMORY;
  3068. BAIL_ON_FAILURE(hr);
  3069. }
  3070. memcpy( aModsBuffer, **aMods, *pdwNumOfMods * sizeof(LDAPModW));
  3071. FreeADsMem( **aMods );
  3072. FreeADsMem( *aMods );
  3073. *aMods = aModsTemp;
  3074. for ( j = 0; j < *pdwNumOfMods; j++ )
  3075. {
  3076. (*aMods)[j] = &aModsBuffer[j];
  3077. }
  3078. }
  3079. if ( aValuesAdd )
  3080. {
  3081. (*aMods)[j] = &aModsBuffer[j];
  3082. aModsBuffer[j].mod_type = pszPropName;
  3083. aModsBuffer[j].mod_values = aValuesAdd;
  3084. aModsBuffer[j].mod_op |= LDAP_MOD_ADD;
  3085. j++;
  3086. }
  3087. if ( aValuesRemove )
  3088. {
  3089. (*aMods)[j] = &aModsBuffer[j];
  3090. aModsBuffer[j].mod_type = pszPropName;
  3091. aModsBuffer[j].mod_values = aValuesRemove;
  3092. aModsBuffer[j].mod_op |= LDAP_MOD_DELETE;
  3093. }
  3094. *pdwNumOfMods += nCount;
  3095. error:
  3096. RRETURN_EXP_IF_ERR(hr);
  3097. }
  3098. HRESULT
  3099. CLDAPClass::get_NTDSProp_Helper( THIS_ BSTR bstrName, VARIANT FAR *pvProp )
  3100. {
  3101. HRESULT hr = S_OK;
  3102. LPTSTR *aValues = NULL;
  3103. int nCount = 0;
  3104. LDAPMessage *res = NULL;
  3105. LDAPMessage *e = NULL;
  3106. LPTSTR aStrings[3];
  3107. aStrings[0] = TEXT("cn");
  3108. aStrings[1] = bstrName;
  3109. aStrings[2] = NULL;
  3110. if ( _pClassInfo == NULL ) // new class
  3111. {
  3112. hr = MakeVariantFromStringArray( NULL,
  3113. pvProp );
  3114. RRETURN_EXP_IF_ERR(hr);
  3115. }
  3116. //
  3117. // If the dn is NULL we have not got the info so fetch it.
  3118. //
  3119. if (_pszLDAPDn == NULL )
  3120. {
  3121. hr = BuildSchemaLDAPPathAndGetAttribute(
  3122. _Parent,
  3123. _Name,
  3124. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  3125. _pClassInfo == NULL,
  3126. _Credentials,
  3127. aStrings,
  3128. &_pszLDAPServer,
  3129. &_pszLDAPDn,
  3130. &_ld,
  3131. &res
  3132. );
  3133. BAIL_IF_ERROR(hr);
  3134. hr = LdapFirstEntry(
  3135. _ld,
  3136. res,
  3137. &e
  3138. );
  3139. BAIL_IF_ERROR(hr);
  3140. hr = LdapGetValues(
  3141. _ld,
  3142. e,
  3143. bstrName,
  3144. &aValues,
  3145. &nCount
  3146. );
  3147. }
  3148. else
  3149. {
  3150. hr = LdapReadAttribute(
  3151. _pszLDAPServer,
  3152. _pszLDAPDn,
  3153. bstrName,
  3154. &aValues,
  3155. &nCount,
  3156. _Credentials,
  3157. _dwPort
  3158. );
  3159. }
  3160. if ( hr == HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) )
  3161. {
  3162. hr = NO_ERROR;
  3163. }
  3164. BAIL_IF_ERROR(hr);
  3165. hr = MakeVariantFromStringArray( aValues,
  3166. pvProp );
  3167. BAIL_IF_ERROR(hr);
  3168. hr = put_VARIANT_Property( this, bstrName, *pvProp );
  3169. BAIL_IF_ERROR(hr);
  3170. hr = _pPropertyCache->ClearPropertyFlag( bstrName );
  3171. BAIL_IF_ERROR(hr);
  3172. cleanup:
  3173. if ( aValues )
  3174. LdapValueFree( aValues );
  3175. if (res)
  3176. LdapMsgFree(res);
  3177. RRETURN_EXP_IF_ERR(hr);
  3178. }
  3179. //
  3180. // Needed for dynamic dispid's in the property cache.
  3181. //
  3182. HRESULT
  3183. CLDAPClass::GetAttributeSyntax(
  3184. LPWSTR szPropertyName,
  3185. PDWORD pdwSyntaxId
  3186. )
  3187. {
  3188. HRESULT hr;
  3189. hr = LdapGetSyntaxOfAttributeOnServer(
  3190. _pszLDAPServer,
  3191. szPropertyName,
  3192. pdwSyntaxId,
  3193. _Credentials,
  3194. _dwPort
  3195. );
  3196. RRETURN_EXP_IF_ERR(hr);
  3197. }
  3198. /* IUmiHelperPrivate support. */
  3199. //+---------------------------------------------------------------------------
  3200. // Function: CLDAPClass::GetPropertiesHelper
  3201. //
  3202. // Synopsis: Returns an array of PPROPERTYINFO that points to the
  3203. // property definitions this class can hold.
  3204. //
  3205. // Arguments: ppProperties - Ret values for the property info.
  3206. // pdwCount - Ret value for the number of properties.
  3207. //
  3208. //
  3209. // Returns: HRESULT - S_OK or any failure error code.
  3210. //
  3211. // Modifies: ppProperties and pdwCount appropriately.
  3212. //
  3213. //----------------------------------------------------------------------------
  3214. STDMETHODIMP
  3215. CLDAPClass::GetPropertiesHelper(
  3216. void **ppProperties,
  3217. PDWORD pdwPropCount
  3218. )
  3219. {
  3220. HRESULT hr = S_OK;
  3221. PPROPERTYINFO *pPropArray = NULL;
  3222. DWORD dwPropCount = 0;
  3223. DWORD dwCtr;
  3224. SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) _hSchema;
  3225. //
  3226. // Initialize out params to default values.
  3227. //
  3228. *pdwPropCount = 0;
  3229. *ppProperties = NULL;
  3230. //
  3231. // If there is no classInfo then we do not have any further processing
  3232. // to do as there are no properties on this class.
  3233. //
  3234. if (!this->_pClassInfo) {
  3235. RRETURN(E_FAIL);
  3236. }
  3237. //
  3238. // We need to know how many entries are there in the list of properties.
  3239. // The total is made up of both the mandatory and optional properties.
  3240. // Note that we will adjust this value suitably as we process the array.
  3241. //
  3242. dwPropCount = _pClassInfo->nNumOfMayContain
  3243. + _pClassInfo->nNumOfMustContain;
  3244. pPropArray = (PPROPERTYINFO *) AllocADsMem(
  3245. sizeof(PPROPERTY*) * dwPropCount
  3246. );
  3247. if (!pPropArray) {
  3248. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3249. }
  3250. //
  3251. // Go through and get the info for the must contain.
  3252. //
  3253. for (
  3254. dwCtr = 0;
  3255. ((dwCtr < (_pClassInfo->nNumOfMustContain))
  3256. && (_pClassInfo->pOIDsMustContain[dwCtr] != -1));
  3257. dwCtr++)
  3258. {
  3259. //
  3260. // Assign the appropriate prop info ptrs from the may contain list.
  3261. //
  3262. pPropArray[dwCtr] = &(pSchemaInfo->aProperties[
  3263. (pSchemaInfo->aPropertiesSearchTable[
  3264. _pClassInfo->pOIDsMustContain[dwCtr]].nIndex
  3265. )]);
  3266. }
  3267. DWORD dwAdjust;
  3268. //
  3269. // We could have less than the number in the array if we hit -1, or
  3270. // -1 could be pointing correctly to the last element !!!
  3271. //
  3272. if ((_pClassInfo->pOIDsMustContain[dwCtr] == -1)
  3273. && (dwCtr < _pClassInfo->nNumOfMustContain)) {
  3274. dwCtr++;
  3275. }
  3276. dwAdjust = dwCtr;
  3277. //
  3278. // Now get the may contain information.
  3279. //
  3280. for (
  3281. dwCtr = 0;
  3282. ((dwCtr < (_pClassInfo->nNumOfMayContain))
  3283. && (_pClassInfo->pOIDsMayContain[dwCtr]) != -1);
  3284. dwCtr++)
  3285. {
  3286. DWORD dwTemp = dwCtr + dwAdjust;
  3287. pPropArray[dwTemp] = &(pSchemaInfo->aProperties[
  3288. (pSchemaInfo->aPropertiesSearchTable[
  3289. _pClassInfo->pOIDsMayContain[dwCtr]].nIndex
  3290. )]);
  3291. }
  3292. *ppProperties = (void *) pPropArray;
  3293. if ((_pClassInfo->pOIDsMayContain[dwCtr] == -1)
  3294. && (dwCtr < _pClassInfo->nNumOfMustContain)) {
  3295. *pdwPropCount = dwAdjust + dwCtr + 1;
  3296. }
  3297. else {
  3298. *pdwPropCount = dwAdjust + dwCtr;
  3299. }
  3300. error:
  3301. if (FAILED(hr)) {
  3302. if (pPropArray) {
  3303. FreeADsMem(pPropArray);
  3304. }
  3305. }
  3306. RRETURN(hr);
  3307. }
  3308. HRESULT
  3309. IsPropertyInList(
  3310. LPCWSTR pszName,
  3311. VARIANT vProp,
  3312. BOOL *pfInList
  3313. )
  3314. {
  3315. HRESULT hr = S_OK;
  3316. VARIANT *pvProp = &vProp;
  3317. SAFEARRAY *pArray = V_ARRAY(pvProp);
  3318. DWORD dwSLBound;
  3319. DWORD dwSUBound;
  3320. DWORD dwLength = 0;
  3321. VARIANT vVar;
  3322. VariantInit(&vVar);
  3323. *pfInList = FALSE;
  3324. hr = SafeArrayGetLBound(pArray,
  3325. 1,
  3326. (long FAR *)&dwSLBound
  3327. );
  3328. BAIL_ON_FAILURE(hr);
  3329. hr = SafeArrayGetUBound(pArray,
  3330. 1,
  3331. (long FAR *)&dwSUBound
  3332. );
  3333. BAIL_ON_FAILURE(hr);
  3334. dwLength = dwSUBound - dwSLBound;
  3335. //
  3336. // If there are 0 elements in cannot be in the list.
  3337. //
  3338. if (!dwLength) {
  3339. RRETURN(S_OK);
  3340. }
  3341. for (DWORD dwCtr = 0;
  3342. (dwCtr <= dwLength) && (*pfInList != TRUE);
  3343. dwCtr++)
  3344. {
  3345. //
  3346. // Go through the array to see if we find the name in the list.
  3347. //
  3348. VariantClear(&vVar);
  3349. hr = SafeArrayGetElement(pArray,
  3350. (long FAR *)&dwCtr,
  3351. &vVar
  3352. );
  3353. BAIL_ON_FAILURE(hr);
  3354. if (V_VT(&vVar) != VT_BSTR) {
  3355. BAIL_ON_FAILURE(hr = E_FAIL);
  3356. }
  3357. if (!_wcsicmp(pszName, vVar.bstrVal)) {
  3358. *pfInList = TRUE;
  3359. }
  3360. }
  3361. error:
  3362. VariantClear(&vVar);
  3363. RRETURN(hr);
  3364. }
  3365. //+---------------------------------------------------------------------------
  3366. // Function: CLDAPClass::GetOriginHelper
  3367. //
  3368. // Synopsis: Returns the name of the class this property originated on.
  3369. //
  3370. // Arguments: pszName - Name of the property whose origin is needed.
  3371. // pbstrOrigin - Return value - name of class.
  3372. //
  3373. // Returns: HRESULT - S_OK or any failure error code.
  3374. //
  3375. // Modifies: pbstrOrigin on success.
  3376. //
  3377. //----------------------------------------------------------------------------
  3378. STDMETHODIMP
  3379. CLDAPClass::GetOriginHelper(
  3380. LPCWSTR pszName,
  3381. BSTR *pbstrOrigin
  3382. )
  3383. {
  3384. HRESULT hr = S_OK;
  3385. CCredentials cCreds = _Credentials;
  3386. IUnknown *pUnk = NULL;
  3387. IADsContainer *pContainer = NULL;
  3388. BSTR bstrTemp = NULL;
  3389. DWORD dwAuthFlags = cCreds.GetAuthFlags();
  3390. BOOL fDone = FALSE;
  3391. BOOL fInMustContain = FALSE;
  3392. BOOL fInList = FALSE;
  3393. IADsClass *pClass = NULL;
  3394. IDispatch *pDispObj = NULL;
  3395. BOOL fMustContain = FALSE;
  3396. VARIANT vVar, vVarProps;
  3397. VariantInit(&vVar);
  3398. VariantInit(&vVarProps);
  3399. //
  3400. // If we are already at the top.
  3401. //
  3402. if (!_wcsicmp(_Name, L"top")) {
  3403. hr = ADsAllocString(L"top", pbstrOrigin);
  3404. RRETURN(hr);
  3405. }
  3406. //
  3407. // We want to chase up either the mandatory or optional list and
  3408. // not both. So we first update this flag.
  3409. //
  3410. hr = get_MandatoryProperties(&vVarProps);
  3411. BAIL_ON_FAILURE(hr);
  3412. hr = IsPropertyInList(pszName, vVarProps, &fInMustContain);
  3413. BAIL_ON_FAILURE(hr)
  3414. //
  3415. // Mask out the reserved flags - we want to be in ADSI land now.
  3416. //
  3417. cCreds.SetAuthFlags(dwAuthFlags & ~(ADS_AUTH_RESERVED));
  3418. //
  3419. // This will be the default class name to return.
  3420. //
  3421. hr = ADsAllocString(_Name, &bstrTemp);
  3422. BAIL_ON_FAILURE(hr);
  3423. //
  3424. // Need to get hold of the schema container.
  3425. //
  3426. hr = GetObject(_Parent, cCreds, (void **)&pUnk);
  3427. BAIL_ON_FAILURE(hr);
  3428. hr = pUnk->QueryInterface(IID_IADsContainer, (void **) &pContainer);
  3429. BAIL_ON_FAILURE(hr);
  3430. while (!fDone) {
  3431. //
  3432. // Need to keep finding the derived from until we hit top
  3433. // or we hit a class that does not support the attribute.
  3434. //
  3435. VariantClear(&vVar);
  3436. VariantClear(&vVarProps);
  3437. if (pDispObj) {
  3438. pDispObj->Release();
  3439. pDispObj = NULL;
  3440. }
  3441. if (!pClass) {
  3442. //
  3443. // Need to get the derived from for the current class.
  3444. //
  3445. hr = get_DerivedFrom(&vVar);
  3446. }
  3447. else {
  3448. hr = pClass->get_DerivedFrom(&vVar);
  3449. pClass->Release();
  3450. pClass = NULL;
  3451. }
  3452. //
  3453. // Get the derived from classes object.
  3454. //
  3455. hr = pContainer->GetObject(
  3456. L"Class",
  3457. vVar.bstrVal,
  3458. &pDispObj
  3459. );
  3460. BAIL_ON_FAILURE(hr);
  3461. hr = pDispObj->QueryInterface(
  3462. IID_IADsClass,
  3463. (void **) &pClass
  3464. );
  3465. BAIL_ON_FAILURE(hr);
  3466. if (!_wcsicmp(vVar.bstrVal, L"top")) {
  3467. fDone = TRUE;
  3468. }
  3469. if (fInMustContain) {
  3470. hr = pClass->get_MandatoryProperties(&vVarProps);
  3471. }
  3472. else {
  3473. hr = pClass->get_OptionalProperties(&vVarProps);
  3474. }
  3475. BAIL_ON_FAILURE(hr);
  3476. hr = IsPropertyInList(pszName, vVarProps, &fInList);
  3477. BAIL_ON_FAILURE(hr);
  3478. if (!fInList) {
  3479. //
  3480. // The value in temp is the correct class name
  3481. //
  3482. hr = ADsAllocString(bstrTemp, pbstrOrigin);
  3483. BAIL_ON_FAILURE(hr);
  3484. fDone = TRUE;
  3485. }
  3486. //
  3487. // This will be true only if we found the item in top.
  3488. //
  3489. if (fInList && fDone) {
  3490. hr = ADsAllocString(L"Top", pbstrOrigin);
  3491. BAIL_ON_FAILURE(hr);
  3492. }
  3493. if (bstrTemp) {
  3494. SysFreeString(bstrTemp);
  3495. bstrTemp = NULL;
  3496. }
  3497. //
  3498. // Need to get the current class name in bstrTemp.
  3499. //
  3500. hr = ADsAllocString(vVar.bstrVal, &bstrTemp);
  3501. BAIL_ON_FAILURE(hr);
  3502. }
  3503. //
  3504. // We will default to the current class.
  3505. //
  3506. if (!pbstrOrigin) {
  3507. hr = ADsAllocString(_Name, pbstrOrigin);
  3508. BAIL_ON_FAILURE(hr);
  3509. }
  3510. error:
  3511. if (bstrTemp) {
  3512. SysFreeString(bstrTemp);
  3513. }
  3514. VariantClear(&vVar);
  3515. VariantClear(&vVarProps);
  3516. if (pContainer) {
  3517. pContainer->Release();
  3518. }
  3519. if (pUnk) {
  3520. pUnk->Release();
  3521. }
  3522. if (pClass) {
  3523. pClass->Release();
  3524. }
  3525. if (pDispObj) {
  3526. pDispObj->Release();
  3527. }
  3528. RRETURN(hr);
  3529. }
  3530. /******************************************************************/
  3531. /* Class CLDAPProperty
  3532. /******************************************************************/
  3533. DEFINE_IDispatch_Implementation(CLDAPProperty)
  3534. DEFINE_IADs_Implementation(CLDAPProperty)
  3535. CLDAPProperty::CLDAPProperty()
  3536. : _pDispMgr( NULL ),
  3537. _pPropertyCache( NULL ),
  3538. _bstrSyntax( NULL ),
  3539. _hSchema( NULL ),
  3540. _pPropertyInfo( NULL ),
  3541. _pszLDAPServer(NULL),
  3542. _pszLDAPDn(NULL),
  3543. _fNTDS( TRUE ),
  3544. _ld( NULL )
  3545. {
  3546. ENLIST_TRACKING(CLDAPProperty);
  3547. }
  3548. CLDAPProperty::~CLDAPProperty()
  3549. {
  3550. delete _pDispMgr;
  3551. delete _pPropertyCache;
  3552. if ( _bstrSyntax ) {
  3553. ADsFreeString( _bstrSyntax );
  3554. }
  3555. if ( _hSchema ) {
  3556. SchemaClose( &_hSchema );
  3557. _hSchema = NULL;
  3558. }
  3559. if (_pszLDAPServer) {
  3560. FreeADsStr(_pszLDAPServer);
  3561. }
  3562. if (_pszLDAPDn) {
  3563. FreeADsStr(_pszLDAPDn);
  3564. }
  3565. if ( _ld ) {
  3566. LdapCloseObject( _ld );
  3567. _ld = NULL;
  3568. }
  3569. }
  3570. HRESULT
  3571. CLDAPProperty::CreateProperty(
  3572. BSTR bstrParent,
  3573. LDAP_SCHEMA_HANDLE hSchema,
  3574. BSTR bstrName,
  3575. PROPERTYINFO *pPropertyInfo,
  3576. CCredentials& Credentials,
  3577. DWORD dwObjectState,
  3578. REFIID riid,
  3579. void **ppvObj
  3580. )
  3581. {
  3582. CLDAPProperty FAR * pProperty = NULL;
  3583. HRESULT hr = S_OK;
  3584. BSTR bstrSyntax = NULL;
  3585. OBJECTINFO ObjectInfo;
  3586. POBJECTINFO pObjectInfo = &ObjectInfo;
  3587. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  3588. hr = AllocatePropertyObject(Credentials, &pProperty );
  3589. BAIL_ON_FAILURE(hr);
  3590. pProperty->_pPropertyInfo = pPropertyInfo;
  3591. SchemaAddRef( hSchema );
  3592. pProperty->_hSchema = hSchema;
  3593. if ( pPropertyInfo )
  3594. {
  3595. hr = put_BSTR_Property( pProperty, TEXT("attributeID"),
  3596. pPropertyInfo->pszOID);
  3597. if ( SUCCEEDED(hr))
  3598. {
  3599. hr = put_VARIANT_BOOL_Property( pProperty, TEXT("isSingleValued"),
  3600. (VARIANT_BOOL)pPropertyInfo->fSingleValued );
  3601. BAIL_ON_FAILURE(hr);
  3602. pProperty->_pPropertyCache->ClearAllPropertyFlags();
  3603. pProperty->_fNTDS = TRUE;
  3604. }
  3605. else
  3606. {
  3607. pProperty->_fNTDS = FALSE;
  3608. }
  3609. }
  3610. hr = ADsObject(bstrParent, pObjectInfo);
  3611. BAIL_ON_FAILURE(hr);
  3612. pProperty->_dwPort = pObjectInfo->PortNumber;
  3613. FreeObjectInfo(pObjectInfo);
  3614. pObjectInfo = NULL;
  3615. hr = pProperty->InitializeCoreObject(
  3616. bstrParent,
  3617. bstrName,
  3618. PROPERTY_CLASS_NAME,
  3619. CLSID_LDAPProperty,
  3620. dwObjectState );
  3621. BAIL_ON_FAILURE(hr);
  3622. //
  3623. // At this point update the info in the property cache
  3624. //
  3625. pProperty->_pPropertyCache->SetObjInformation(
  3626. &(pProperty->_Credentials),
  3627. pProperty->_pszLDAPServer,
  3628. pProperty->_dwPort
  3629. );
  3630. BAIL_ON_FAILURE(hr);
  3631. //
  3632. // Need to create the umi object if applicable.
  3633. //
  3634. if (Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
  3635. hr = ((CCoreADsObject*)pProperty)->InitUmiObject(
  3636. IntfPropsSchema,
  3637. pProperty->_pPropertyCache,
  3638. (IADs *) pProperty,
  3639. (IADs *) pProperty,
  3640. riid,
  3641. ppvObj,
  3642. &(pProperty->_Credentials),
  3643. pProperty->_dwPort,
  3644. pProperty->_pszLDAPServer,
  3645. pProperty->_pszLDAPDn
  3646. );
  3647. BAIL_ON_FAILURE(hr);
  3648. //
  3649. // Need to put syntax in the cache.
  3650. //
  3651. if (pProperty->_pPropertyInfo->pszSyntax) {
  3652. hr = GetFriendlyNameFromOID(
  3653. pProperty->_pPropertyInfo->pszSyntax,
  3654. &bstrSyntax
  3655. );
  3656. if (FAILED(hr)) {
  3657. //
  3658. // ok if this failed.
  3659. //
  3660. hr = S_OK;
  3661. }
  3662. else {
  3663. hr = put_BSTR_Property(
  3664. pProperty, TEXT("syntax"),
  3665. bstrSyntax
  3666. );
  3667. SysFreeString(bstrSyntax);
  3668. //
  3669. // Not critical failure
  3670. //
  3671. hr = S_OK;
  3672. }
  3673. }
  3674. //
  3675. // Name is a simulated propert used for UMI.
  3676. //
  3677. hr = put_BSTR_Property(
  3678. pProperty,
  3679. TEXT("Name"),
  3680. bstrName
  3681. );
  3682. BAIL_ON_FAILURE(hr);
  3683. RRETURN(S_OK);
  3684. }
  3685. //
  3686. // Get the LDAP path of the schema entry
  3687. //
  3688. hr = pProperty->QueryInterface( riid, ppvObj );
  3689. BAIL_ON_FAILURE(hr);
  3690. pProperty->Release();
  3691. RRETURN(hr);
  3692. error:
  3693. *ppvObj = NULL;
  3694. delete pProperty;
  3695. FreeObjectInfo(pObjectInfo);
  3696. RRETURN_EXP_IF_ERR(hr);
  3697. }
  3698. STDMETHODIMP
  3699. CLDAPProperty::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  3700. {
  3701. if (ppv == NULL) {
  3702. RRETURN(E_POINTER);
  3703. }
  3704. if (IsEqualIID(iid, IID_IUnknown))
  3705. {
  3706. *ppv = (IADsProperty FAR *) this;
  3707. }
  3708. else if (IsEqualIID(iid, IID_IDispatch))
  3709. {
  3710. *ppv = (IADs FAR *) this;
  3711. }
  3712. else if (IsEqualIID(iid, IID_ISupportErrorInfo))
  3713. {
  3714. *ppv = (ISupportErrorInfo FAR *) this;
  3715. }
  3716. else if (IsEqualIID(iid, IID_IADs))
  3717. {
  3718. *ppv = (IADs FAR *) this;
  3719. }
  3720. else if (IsEqualIID(iid, IID_IADsProperty))
  3721. {
  3722. *ppv = (IADsProperty FAR *) this;
  3723. }
  3724. else
  3725. {
  3726. *ppv = NULL;
  3727. return E_NOINTERFACE;
  3728. }
  3729. AddRef();
  3730. return NOERROR;
  3731. }
  3732. /* ISupportErrorInfo method */
  3733. STDMETHODIMP
  3734. CLDAPProperty::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
  3735. {
  3736. if (IsEqualIID(riid, IID_IADs) |
  3737. IsEqualIID(riid, IID_IADsProperty)) {
  3738. RRETURN(S_OK);
  3739. } else {
  3740. RRETURN(S_FALSE);
  3741. }
  3742. }
  3743. /* IADs methods */
  3744. STDMETHODIMP
  3745. CLDAPProperty::SetInfo(THIS)
  3746. {
  3747. HRESULT hr = S_OK;
  3748. BOOL fChanged = FALSE;
  3749. if ( !_fNTDS )
  3750. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  3751. if ( GetObjectState() == ADS_OBJECT_UNBOUND )
  3752. {
  3753. hr = LDAPCreateObject();
  3754. BAIL_ON_FAILURE(hr);
  3755. fChanged = TRUE;
  3756. //
  3757. // If the create succeded, set the object type to bound
  3758. //
  3759. SetObjectState(ADS_OBJECT_BOUND);
  3760. }
  3761. else
  3762. {
  3763. hr = LDAPSetObject( &fChanged );
  3764. BAIL_ON_FAILURE(hr);
  3765. }
  3766. //
  3767. // Need to refresh the schema
  3768. //
  3769. if ( SUCCEEDED(hr) && fChanged )
  3770. hr = LDAPRefreshSchema();
  3771. error:
  3772. RRETURN_EXP_IF_ERR(hr);
  3773. }
  3774. HRESULT
  3775. CLDAPProperty::LDAPSetObject( BOOL *pfChanged )
  3776. {
  3777. HRESULT hr = S_OK;
  3778. LDAPModW **aMod = NULL;
  3779. BOOL fNTSecDes = FALSE;
  3780. SECURITY_INFORMATION NewSeInfo;
  3781. *pfChanged = FALSE;
  3782. hr = _pPropertyCache->LDAPMarshallProperties(
  3783. &aMod,
  3784. &fNTSecDes,
  3785. &NewSeInfo
  3786. );
  3787. BAIL_ON_FAILURE(hr);
  3788. if ( aMod == NULL ) // There are no changes that needs to be modified
  3789. RRETURN(S_OK);
  3790. if ( _pszLDAPDn == NULL )
  3791. {
  3792. hr = BuildSchemaLDAPPath( _Parent,
  3793. _Name,
  3794. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  3795. &_pszLDAPServer,
  3796. &_pszLDAPDn,
  3797. _pPropertyInfo == NULL,
  3798. &_ld,
  3799. _Credentials
  3800. );
  3801. BAIL_ON_FAILURE(hr);
  3802. }
  3803. if ( _ld == NULL )
  3804. {
  3805. hr = LdapOpenObject(
  3806. _pszLDAPServer,
  3807. _pszLDAPDn,
  3808. &_ld,
  3809. _Credentials,
  3810. _dwPort
  3811. );
  3812. BAIL_ON_FAILURE(hr);
  3813. }
  3814. hr = LdapModifyS(
  3815. _ld,
  3816. _pszLDAPDn,
  3817. aMod
  3818. );
  3819. BAIL_ON_FAILURE(hr);
  3820. // We are successful at this point,
  3821. // So, clean up the flags in the cache so the same operation
  3822. // won't be repeated on the next SetInfo()
  3823. _pPropertyCache->ClearAllPropertyFlags();
  3824. *pfChanged = TRUE;
  3825. error:
  3826. if (aMod) {
  3827. if ( *aMod )
  3828. FreeADsMem( *aMod );
  3829. FreeADsMem( aMod );
  3830. }
  3831. RRETURN_EXP_IF_ERR(hr);
  3832. }
  3833. HRESULT
  3834. CLDAPProperty::LDAPCreateObject()
  3835. {
  3836. HRESULT hr = S_OK;
  3837. LDAPModW **aMod = NULL;
  3838. DWORD dwIndex = 0;
  3839. VARIANT v;
  3840. BOOL fNTSecDes= FALSE;
  3841. SECURITY_INFORMATION NewSeInfo;
  3842. //
  3843. // Get the LDAP path of the schema entry
  3844. //
  3845. if ( (_pszLDAPServer == NULL) && (_pszLDAPDn == NULL))
  3846. {
  3847. hr = BuildSchemaLDAPPath( _Parent,
  3848. _Name,
  3849. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  3850. &_pszLDAPServer,
  3851. &_pszLDAPDn,
  3852. _pPropertyInfo == NULL,
  3853. &_ld,
  3854. _Credentials
  3855. );
  3856. BAIL_ON_FAILURE(hr);
  3857. }
  3858. if ( _pPropertyCache->findproperty( TEXT("objectClass"), &dwIndex )
  3859. == E_ADS_PROPERTY_NOT_FOUND )
  3860. {
  3861. VariantInit(&v);
  3862. v.vt = VT_BSTR;
  3863. V_BSTR(&v) = NT_SCHEMA_PROPERTY_NAME;
  3864. hr = Put( TEXT("objectClass"), v );
  3865. BAIL_ON_FAILURE(hr);
  3866. }
  3867. if ( _pPropertyCache->findproperty( TEXT("cn"), &dwIndex )
  3868. == E_ADS_PROPERTY_NOT_FOUND )
  3869. {
  3870. VariantInit(&v);
  3871. v.vt = VT_BSTR;
  3872. V_BSTR(&v) = _Name;
  3873. hr = Put( TEXT("cn"), v );
  3874. BAIL_ON_FAILURE(hr);
  3875. }
  3876. if ( _pPropertyCache->findproperty( TEXT("lDAPDisplayName"), &dwIndex )
  3877. == E_ADS_PROPERTY_NOT_FOUND )
  3878. {
  3879. VariantInit(&v);
  3880. v.vt = VT_BSTR;
  3881. V_BSTR(&v) = _Name;
  3882. hr = Put( TEXT("lDAPDisplayName"), v );
  3883. BAIL_ON_FAILURE(hr);
  3884. }
  3885. hr = _pPropertyCache->LDAPMarshallProperties(
  3886. &aMod,
  3887. &fNTSecDes,
  3888. &NewSeInfo
  3889. );
  3890. BAIL_ON_FAILURE(hr);
  3891. if ( _ld == NULL )
  3892. {
  3893. hr = LdapOpenObject(
  3894. _pszLDAPServer,
  3895. _pszLDAPDn,
  3896. &_ld,
  3897. _Credentials,
  3898. _dwPort
  3899. );
  3900. BAIL_ON_FAILURE(hr);
  3901. }
  3902. hr = LdapAddS(
  3903. _ld,
  3904. _pszLDAPDn,
  3905. aMod
  3906. );
  3907. BAIL_ON_FAILURE(hr);
  3908. // We are successful at this point,
  3909. // So, clean up the flags in the cache so the same operation
  3910. // won't be repeated on the next SetInfo()
  3911. _pPropertyCache->ClearAllPropertyFlags();
  3912. error:
  3913. if (aMod) {
  3914. if ( *aMod )
  3915. FreeADsMem( *aMod );
  3916. FreeADsMem( aMod );
  3917. }
  3918. RRETURN_EXP_IF_ERR(hr);
  3919. }
  3920. HRESULT
  3921. CLDAPProperty::LDAPRefreshSchema(THIS)
  3922. {
  3923. HRESULT hr = S_OK;
  3924. if (( _pszLDAPServer == NULL) && (_pszLDAPDn == NULL))
  3925. {
  3926. hr = BuildSchemaLDAPPath( _Parent,
  3927. _Name,
  3928. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  3929. &_pszLDAPServer,
  3930. &_pszLDAPDn,
  3931. _pPropertyInfo == NULL,
  3932. &_ld,
  3933. _Credentials
  3934. );
  3935. BAIL_ON_FAILURE(hr);
  3936. }
  3937. //
  3938. // Make the old schema obsolete and get the new schema
  3939. // We cannot delete the old schema since other objects might have
  3940. // references to it.
  3941. //
  3942. hr = LdapMakeSchemaCacheObsolete(
  3943. _pszLDAPServer,
  3944. _Credentials,
  3945. _dwPort
  3946. );
  3947. BAIL_ON_FAILURE(hr);
  3948. error:
  3949. RRETURN_EXP_IF_ERR(hr);
  3950. }
  3951. STDMETHODIMP
  3952. CLDAPProperty::GetInfo(THIS)
  3953. {
  3954. HRESULT hr = S_OK;
  3955. BSTR bstrSyntax = NULL;
  3956. if ( GetObjectState() == ADS_OBJECT_UNBOUND )
  3957. RRETURN_EXP_IF_ERR(E_ADS_OBJECT_UNBOUND);
  3958. hr = LDAPRefreshSchema();
  3959. BAIL_ON_FAILURE(hr);
  3960. SchemaClose( &_hSchema );
  3961. hr = SchemaOpen( _pszLDAPServer, &_hSchema, _Credentials, _dwPort );
  3962. BAIL_ON_FAILURE(hr);
  3963. //
  3964. // Find the new property info in the new schemainfo
  3965. //
  3966. hr = SchemaGetPropertyInfo(
  3967. _hSchema,
  3968. _Name,
  3969. &_pPropertyInfo );
  3970. BAIL_ON_FAILURE( hr );
  3971. if ( _pPropertyInfo == NULL )
  3972. {
  3973. // Property name not found, set error
  3974. hr = E_ADS_BAD_PATHNAME;
  3975. BAIL_ON_FAILURE(hr);
  3976. }
  3977. _pPropertyCache->flushpropertycache();
  3978. hr = put_BSTR_Property( this, TEXT("attributeID"),
  3979. _pPropertyInfo->pszOID);
  3980. BAIL_ON_FAILURE(hr);
  3981. if ( _bstrSyntax )
  3982. {
  3983. ADsFreeString( _bstrSyntax );
  3984. _bstrSyntax = NULL;
  3985. }
  3986. hr = put_VARIANT_BOOL_Property( this, TEXT("isSingleValued"),
  3987. (VARIANT_BOOL)_pPropertyInfo->fSingleValued );
  3988. BAIL_ON_FAILURE(hr);
  3989. //
  3990. // If we are calling from Umi land then we need to set
  3991. // additional properties.
  3992. //
  3993. if (_Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
  3994. if (_pPropertyInfo->pszSyntax) {
  3995. hr = GetFriendlyNameFromOID(
  3996. _pPropertyInfo->pszSyntax,
  3997. &bstrSyntax
  3998. );
  3999. if (FAILED(hr)) {
  4000. //
  4001. // ok if this failed.
  4002. //
  4003. hr = S_OK;
  4004. }
  4005. else {
  4006. hr = put_BSTR_Property(
  4007. this, TEXT("syntax"),
  4008. bstrSyntax
  4009. );
  4010. SysFreeString(bstrSyntax);
  4011. //
  4012. // Not critical failure
  4013. //
  4014. hr = S_OK;
  4015. }
  4016. }
  4017. //
  4018. // Name is a simulated propert used for UMI.
  4019. //
  4020. hr = put_BSTR_Property(
  4021. this,
  4022. TEXT("Name"),
  4023. _Name
  4024. );
  4025. BAIL_ON_FAILURE(hr);
  4026. } // special props for Umi.
  4027. if (_fNTDS) {
  4028. hr = GetNTDSSchemaInfo(TRUE);
  4029. }
  4030. _pPropertyCache->ClearAllPropertyFlags();
  4031. _pPropertyCache->setGetInfoFlag();
  4032. error:
  4033. if (bstrSyntax) {
  4034. SysFreeString(bstrSyntax);
  4035. }
  4036. RRETURN_EXP_IF_ERR(hr);
  4037. }
  4038. //
  4039. // Helper function for Umi - defined in CCoreADsObject.
  4040. //
  4041. STDMETHODIMP
  4042. CLDAPProperty::GetInfo(DWORD dwFlags)
  4043. {
  4044. HRESULT hr = S_OK;
  4045. if (dwFlags == GETINFO_FLAG_EXPLICIT) {
  4046. RRETURN(GetInfo());
  4047. }
  4048. else if (_fNTDS
  4049. && dwFlags != GETINFO_FLAG_IMPLICIT_AS_NEEDED
  4050. ) {
  4051. //
  4052. // Read the extra NTDS specific schema properties.
  4053. //
  4054. hr = GetNTDSSchemaInfo(FALSE);
  4055. }
  4056. //
  4057. // Any other flags means nothing to do.
  4058. //
  4059. RRETURN(hr);
  4060. }
  4061. HRESULT
  4062. CLDAPProperty::GetNTDSSchemaInfo(
  4063. BOOL fForce
  4064. )
  4065. {
  4066. HRESULT hr = S_OK;
  4067. LPTSTR aStrings[] = {
  4068. TEXT("cn"),
  4069. TEXT("schemaIDGUID"),
  4070. TEXT("rangeUpper"),
  4071. TEXT("rangeLower"),
  4072. NULL
  4073. };
  4074. LDAPMessage *res = NULL;
  4075. if (_pszLDAPDn == NULL) {
  4076. //
  4077. // Need to get the dn for this object and also
  4078. // the attributes we are interested in.
  4079. //
  4080. hr = BuildSchemaLDAPPathAndGetAttribute(
  4081. _Parent,
  4082. _Name,
  4083. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  4084. _pPropertyInfo == NULL,
  4085. _Credentials,
  4086. aStrings,
  4087. &_pszLDAPServer,
  4088. &_pszLDAPDn,
  4089. &_ld,
  4090. &res
  4091. );
  4092. }
  4093. else {
  4094. //
  4095. // Looks like we just need the attributes in this case.
  4096. //
  4097. hr = LdapSearchS(
  4098. _ld,
  4099. _pszLDAPDn,
  4100. LDAP_SCOPE_BASE,
  4101. L"(objectClass=*)",
  4102. aStrings,
  4103. FALSE,
  4104. &res
  4105. );
  4106. }
  4107. BAIL_ON_FAILURE(hr);
  4108. //
  4109. // If we succeeded we should unmarshall properties into the cache.
  4110. //
  4111. hr = _pPropertyCache->LDAPUnMarshallProperties(
  4112. _pszLDAPServer,
  4113. _ld,
  4114. res,
  4115. fForce,
  4116. _Credentials
  4117. );
  4118. BAIL_ON_FAILURE(hr);
  4119. _pPropertyCache->setGetInfoFlag();
  4120. error:
  4121. if (res) {
  4122. LdapMsgFree(res);
  4123. }
  4124. RRETURN(hr);
  4125. }
  4126. STDMETHODIMP
  4127. CLDAPProperty::Get(THIS_ BSTR bstrName, VARIANT FAR* pvProp)
  4128. {
  4129. HRESULT hr = S_OK;
  4130. DWORD dwSyntaxId;
  4131. LDAPOBJECTARRAY ldapSrcObjects;
  4132. DWORD dwStatus = 0;
  4133. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  4134. //
  4135. // For folks who know now what they do.
  4136. //
  4137. if (!pvProp) {
  4138. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  4139. }
  4140. //
  4141. // retrieve data object from cache; if one exists
  4142. //
  4143. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  4144. hr = _pPropertyCache->unboundgetproperty(
  4145. bstrName,
  4146. &dwSyntaxId,
  4147. &dwStatus,
  4148. &ldapSrcObjects
  4149. );
  4150. // For backward compatibility
  4151. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  4152. hr = E_FAIL;
  4153. }
  4154. } else {
  4155. hr = _pPropertyCache->getproperty(
  4156. bstrName,
  4157. &dwSyntaxId,
  4158. &dwStatus,
  4159. &ldapSrcObjects
  4160. );
  4161. // For backward compatibility
  4162. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  4163. hr = E_ADS_PROPERTY_NOT_FOUND;
  4164. }
  4165. }
  4166. BAIL_ON_FAILURE(hr);
  4167. //
  4168. // translate the Ldap objects to variants
  4169. //
  4170. if ( ldapSrcObjects.dwCount == 1 ) {
  4171. hr = LdapTypeToVarTypeCopy(
  4172. _pszLDAPServer,
  4173. _Credentials,
  4174. ldapSrcObjects.pLdapObjects,
  4175. dwSyntaxId,
  4176. pvProp
  4177. );
  4178. } else {
  4179. hr = LdapTypeToVarTypeCopyConstruct(
  4180. _pszLDAPServer,
  4181. _Credentials,
  4182. ldapSrcObjects,
  4183. dwSyntaxId,
  4184. pvProp
  4185. );
  4186. }
  4187. BAIL_ON_FAILURE(hr);
  4188. error:
  4189. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  4190. RRETURN_EXP_IF_ERR(hr);
  4191. }
  4192. STDMETHODIMP
  4193. CLDAPProperty::Put(THIS_ BSTR bstrName, VARIANT vProp)
  4194. {
  4195. HRESULT hr = S_OK;
  4196. DWORD dwSyntaxId = 0;
  4197. DWORD dwIndex = 0;
  4198. LDAPOBJECTARRAY ldapDestObjects;
  4199. DWORD dwNumValues = 0;
  4200. VARIANT * pVarArray = NULL;
  4201. VARIANT * pvProp = NULL;
  4202. VARIANT vDefProp;
  4203. VariantInit(&vDefProp);
  4204. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  4205. hr = SchemaGetSyntaxOfAttribute( _hSchema, bstrName, &dwSyntaxId );
  4206. if (FAILED(hr)) {
  4207. //
  4208. // Need to see if this is syntax if so we special case
  4209. // for Umi Objects.
  4210. //
  4211. if (!_wcsicmp(L"syntax", bstrName)) {
  4212. dwSyntaxId = LDAPTYPE_CASEIGNORESTRING;
  4213. hr = S_OK;
  4214. }
  4215. }
  4216. BAIL_ON_FAILURE(hr);
  4217. if ( dwSyntaxId == LDAPTYPE_UNKNOWN )
  4218. {
  4219. hr = E_ADS_CANT_CONVERT_DATATYPE;
  4220. BAIL_ON_FAILURE(hr);
  4221. }
  4222. //
  4223. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  4224. // We should dereference a VT_BYREF|VT_VARIANT once and see
  4225. // what's inside.
  4226. //
  4227. pvProp = &vProp;
  4228. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  4229. pvProp = V_VARIANTREF(&vProp);
  4230. }
  4231. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  4232. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  4233. hr = ConvertSafeArrayToVariantArray(
  4234. *pvProp,
  4235. &pVarArray,
  4236. &dwNumValues
  4237. );
  4238. // returns E_FAIL if *pvProp is invalid
  4239. if (hr == E_FAIL)
  4240. hr = E_ADS_BAD_PARAMETER;
  4241. BAIL_ON_FAILURE(hr);
  4242. pvProp = pVarArray;
  4243. }else {
  4244. //
  4245. // If pvProp is a reference to a fundamental type,
  4246. // we have to dereference it once.
  4247. //
  4248. if (V_ISBYREF(pvProp)) {
  4249. hr = VariantCopyInd(&vDefProp, pvProp);
  4250. BAIL_ON_FAILURE(hr);
  4251. pvProp = &vDefProp;
  4252. }
  4253. dwNumValues = 1;
  4254. }
  4255. #if 0
  4256. //
  4257. // check if this is a legal property for this object,
  4258. //
  4259. hr = ValidatePropertyinCache(
  4260. szLDAPTreeName,
  4261. _ADsClass,
  4262. bstrName,
  4263. &dwSyntaxId
  4264. );
  4265. BAIL_ON_FAILURE(hr);
  4266. #endif
  4267. //
  4268. // check if the variant maps to the syntax of this property
  4269. //
  4270. if ( dwNumValues > 0 )
  4271. {
  4272. hr = VarTypeToLdapTypeCopyConstruct(
  4273. _pszLDAPServer,
  4274. _Credentials,
  4275. dwSyntaxId,
  4276. pvProp,
  4277. dwNumValues,
  4278. &ldapDestObjects
  4279. );
  4280. BAIL_ON_FAILURE(hr);
  4281. }
  4282. //
  4283. // Find this property in the cache
  4284. //
  4285. hr = _pPropertyCache->findproperty(
  4286. bstrName,
  4287. &dwIndex
  4288. );
  4289. //
  4290. // If this property does not exist in the
  4291. // cache, add this property into the cache.
  4292. //
  4293. if (FAILED(hr)) {
  4294. hr = _pPropertyCache->addproperty( bstrName );
  4295. BAIL_ON_FAILURE(hr);
  4296. }
  4297. //
  4298. // Now update the property in the cache
  4299. //
  4300. hr = _pPropertyCache->putproperty(
  4301. bstrName,
  4302. PROPERTY_UPDATE,
  4303. dwSyntaxId,
  4304. ldapDestObjects
  4305. );
  4306. BAIL_ON_FAILURE(hr);
  4307. error:
  4308. VariantClear(&vDefProp);
  4309. LdapTypeFreeLdapObjects( &ldapDestObjects );
  4310. if (pVarArray) {
  4311. DWORD i = 0;
  4312. for (i = 0; i < dwNumValues; i++) {
  4313. VariantClear(pVarArray + i);
  4314. }
  4315. FreeADsMem(pVarArray);
  4316. }
  4317. RRETURN_EXP_IF_ERR(hr);
  4318. }
  4319. STDMETHODIMP
  4320. CLDAPProperty::GetEx(THIS_ BSTR bstrName, VARIANT FAR* pvProp)
  4321. {
  4322. HRESULT hr = S_OK;
  4323. DWORD dwSyntaxId;
  4324. DWORD dwNumValues;
  4325. DWORD dwStatus = 0;
  4326. LDAPOBJECTARRAY ldapSrcObjects;
  4327. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  4328. //
  4329. // For those who know no not what they do
  4330. //
  4331. if (!pvProp) {
  4332. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  4333. }
  4334. //
  4335. // retrieve data object from cache; if one exists
  4336. //
  4337. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  4338. hr = _pPropertyCache->unboundgetproperty(
  4339. bstrName,
  4340. &dwSyntaxId,
  4341. &dwStatus,
  4342. &ldapSrcObjects
  4343. );
  4344. // For backward compatibility
  4345. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  4346. hr = E_FAIL;
  4347. }
  4348. } else {
  4349. hr = _pPropertyCache->getproperty(
  4350. bstrName,
  4351. &dwSyntaxId,
  4352. &dwStatus,
  4353. &ldapSrcObjects
  4354. );
  4355. // For backward compatibility
  4356. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  4357. hr = E_ADS_PROPERTY_NOT_FOUND;
  4358. }
  4359. }
  4360. BAIL_ON_FAILURE(hr);
  4361. //
  4362. // translate the Ldap objects to variants
  4363. //
  4364. hr = LdapTypeToVarTypeCopyConstruct(
  4365. _pszLDAPServer,
  4366. _Credentials,
  4367. ldapSrcObjects,
  4368. dwSyntaxId,
  4369. pvProp
  4370. );
  4371. BAIL_ON_FAILURE(hr);
  4372. error:
  4373. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  4374. RRETURN_EXP_IF_ERR(hr);
  4375. }
  4376. STDMETHODIMP
  4377. CLDAPProperty::PutEx(THIS_ long lnControlCode, BSTR bstrName, VARIANT vProp)
  4378. {
  4379. HRESULT hr = S_OK;
  4380. DWORD dwSyntaxId = 0;
  4381. DWORD dwFlags = 0;
  4382. DWORD dwIndex = 0;
  4383. LDAPOBJECTARRAY ldapDestObjects;
  4384. DWORD dwNumValues = 0;
  4385. VARIANT * pVarArray = NULL;
  4386. VARIANT * pvProp = NULL;
  4387. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  4388. switch (lnControlCode) {
  4389. case ADS_PROPERTY_CLEAR:
  4390. dwFlags = PROPERTY_DELETE;
  4391. break;
  4392. case ADS_PROPERTY_UPDATE:
  4393. dwFlags = PROPERTY_UPDATE;
  4394. break;
  4395. default:
  4396. RRETURN_EXP_IF_ERR(hr = E_ADS_BAD_PARAMETER);
  4397. }
  4398. hr = SchemaGetSyntaxOfAttribute( _hSchema, bstrName, &dwSyntaxId );
  4399. BAIL_ON_FAILURE(hr);
  4400. if ( dwSyntaxId == LDAPTYPE_UNKNOWN )
  4401. {
  4402. hr = E_ADS_CANT_CONVERT_DATATYPE;
  4403. BAIL_ON_FAILURE(hr);
  4404. }
  4405. #if 0
  4406. //
  4407. // check if this is a legal property for this object,
  4408. //
  4409. hr = ValidatePropertyinCache(
  4410. szLDAPTreeName,
  4411. _ADsClass,
  4412. bstrName,
  4413. &dwSyntaxId
  4414. );
  4415. BAIL_ON_FAILURE(hr);
  4416. #endif
  4417. if ( dwFlags != PROPERTY_DELETE )
  4418. {
  4419. //
  4420. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  4421. // We should dereference a VT_BYREF|VT_VARIANT once and see
  4422. // what's inside.
  4423. //
  4424. pvProp = &vProp;
  4425. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  4426. pvProp = V_VARIANTREF(&vProp);
  4427. }
  4428. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  4429. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  4430. hr = ConvertSafeArrayToVariantArray(
  4431. *pvProp,
  4432. &pVarArray,
  4433. &dwNumValues
  4434. );
  4435. // returns E_FAIL if *pvProp is invalid
  4436. if (hr == E_FAIL)
  4437. hr = E_ADS_BAD_PARAMETER;
  4438. BAIL_ON_FAILURE(hr);
  4439. pvProp = pVarArray;
  4440. } else {
  4441. hr = E_FAIL;
  4442. BAIL_ON_FAILURE(hr);
  4443. }
  4444. //
  4445. // check if the variant maps to the syntax of this property
  4446. //
  4447. if ( dwNumValues > 0 )
  4448. {
  4449. hr = VarTypeToLdapTypeCopyConstruct(
  4450. _pszLDAPServer,
  4451. _Credentials,
  4452. dwSyntaxId,
  4453. pvProp,
  4454. dwNumValues,
  4455. &ldapDestObjects
  4456. );
  4457. BAIL_ON_FAILURE(hr);
  4458. }
  4459. }
  4460. //
  4461. // Find this property in the cache
  4462. //
  4463. hr = _pPropertyCache->findproperty(
  4464. bstrName,
  4465. &dwIndex
  4466. );
  4467. //
  4468. // If this property does not exist in the
  4469. // cache, add this property into the cache.
  4470. //
  4471. if (FAILED(hr)) {
  4472. hr = _pPropertyCache->addproperty( bstrName );
  4473. BAIL_ON_FAILURE(hr);
  4474. }
  4475. //
  4476. // Now update the property in the cache
  4477. //
  4478. hr = _pPropertyCache->putproperty(
  4479. bstrName,
  4480. PROPERTY_UPDATE,
  4481. dwSyntaxId,
  4482. ldapDestObjects
  4483. );
  4484. BAIL_ON_FAILURE(hr);
  4485. error:
  4486. LdapTypeFreeLdapObjects( &ldapDestObjects );
  4487. if (pVarArray) {
  4488. DWORD i = 0;
  4489. for (i = 0; i < dwNumValues; i++) {
  4490. VariantClear(pVarArray + i);
  4491. }
  4492. FreeADsMem(pVarArray);
  4493. }
  4494. RRETURN_EXP_IF_ERR(hr);
  4495. }
  4496. STDMETHODIMP
  4497. CLDAPProperty::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
  4498. {
  4499. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4500. }
  4501. /* IADsProperty methods */
  4502. STDMETHODIMP
  4503. CLDAPProperty::get_OID( THIS_ BSTR FAR *retval )
  4504. {
  4505. HRESULT hr;
  4506. if ( !retval )
  4507. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4508. if ( _fNTDS )
  4509. {
  4510. GET_PROPERTY_BSTR( this, attributeID );
  4511. }
  4512. else if ( _pPropertyInfo )
  4513. {
  4514. hr = ADsAllocString( _pPropertyInfo->pszOID?
  4515. _pPropertyInfo->pszOID : TEXT(""), retval);
  4516. }
  4517. else
  4518. {
  4519. hr = ADsAllocString( TEXT(""), retval );
  4520. }
  4521. RRETURN_EXP_IF_ERR(hr);
  4522. }
  4523. STDMETHODIMP
  4524. CLDAPProperty::put_OID( THIS_ BSTR bstrOID )
  4525. {
  4526. if ( !_fNTDS )
  4527. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4528. HRESULT hr = put_BSTR_Property( this, TEXT("attributeID"), bstrOID );
  4529. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4530. {
  4531. _fNTDS = FALSE;
  4532. hr = E_NOTIMPL;
  4533. }
  4534. RRETURN_EXP_IF_ERR(hr);
  4535. }
  4536. STDMETHODIMP
  4537. CLDAPProperty::get_Syntax( THIS_ BSTR FAR *retval )
  4538. {
  4539. HRESULT hr = S_OK;
  4540. if ( !retval )
  4541. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4542. if ( _fNTDS )
  4543. {
  4544. if ( _bstrSyntax ) // New property or syntax has been reset
  4545. {
  4546. hr = ADsAllocString( _bstrSyntax, retval);
  4547. } else if (_pPropertyInfo && !_pPropertyInfo->pszSyntax) {
  4548. //
  4549. // New property but syntax has not been set
  4550. //
  4551. hr = E_ADS_PROPERTY_NOT_FOUND;
  4552. }
  4553. }
  4554. //
  4555. // Need to return if hr or retVal as we have what we need
  4556. //
  4557. if (FAILED(hr) || _bstrSyntax) {
  4558. RRETURN_EXP_IF_ERR(hr);
  4559. }
  4560. // If we have the syntax in _pPropertyInfo we need to
  4561. // continue and see if we can get a friendly name to return.
  4562. if ( _pPropertyInfo ) {
  4563. if (_pPropertyInfo->pszSyntax) {
  4564. if (!GetFriendlyNameFromOID(
  4565. _pPropertyInfo->pszSyntax, retval)
  4566. ) {
  4567. // in this case we want to set the retVal
  4568. // to the OID as we could not find a match
  4569. hr = ADsAllocString(_pPropertyInfo->pszSyntax, retval);
  4570. }
  4571. }
  4572. } else {
  4573. hr = ADsAllocString( TEXT(""), retval );
  4574. }
  4575. RRETURN_EXP_IF_ERR(hr);
  4576. }
  4577. STDMETHODIMP
  4578. CLDAPProperty::put_Syntax( THIS_ BSTR bstrSyntax )
  4579. {
  4580. if ( !_fNTDS )
  4581. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4582. LPTSTR pszOID;
  4583. DWORD dwOMSyntax;
  4584. HRESULT hr = S_OK;
  4585. BYTE btDNWithBinary[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x14, 0x01,
  4586. 0x01, 0x01, 0x0B };
  4587. BYTE btDNWithString[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x14, 0x01,
  4588. 0x01, 0x01, 0x0C
  4589. };
  4590. if ( GetSyntaxOID( bstrSyntax, &pszOID, &dwOMSyntax))
  4591. {
  4592. hr = put_BSTR_Property( this, TEXT("attributeSyntax"),
  4593. pszOID );
  4594. BAIL_ON_FAILURE(hr);
  4595. hr = put_LONG_Property( this, TEXT("oMSyntax"),
  4596. dwOMSyntax );
  4597. BAIL_ON_FAILURE(hr);
  4598. if ( _bstrSyntax )
  4599. ADsFreeString( _bstrSyntax );
  4600. hr = ADsAllocString( bstrSyntax, &_bstrSyntax );
  4601. BAIL_ON_FAILURE(hr);
  4602. //
  4603. // We need to handle the special case of DNWithBinary
  4604. // and DNString
  4605. //
  4606. if (_wcsicmp(bstrSyntax, L"DNWithBinary") == 0) {
  4607. //
  4608. // Need to set additional byte attribute
  4609. //
  4610. hr = put_OCTETSTRING_Property(
  4611. this,
  4612. TEXT("omObjectClass"),
  4613. btDNWithBinary,
  4614. (sizeof(btDNWithBinary)/sizeof(btDNWithBinary[0]))
  4615. );
  4616. BAIL_ON_FAILURE(hr);
  4617. }
  4618. else if (_wcsicmp(bstrSyntax, L"DNWithString") == 0) {
  4619. //
  4620. // Need to set omObjectClass here too
  4621. //
  4622. hr = put_OCTETSTRING_Property(
  4623. this,
  4624. TEXT("omObjectClass"),
  4625. btDNWithString,
  4626. (sizeof(btDNWithString)/sizeof(btDNWithString[0]))
  4627. );
  4628. BAIL_ON_FAILURE(hr);
  4629. }
  4630. }
  4631. else
  4632. {
  4633. // Unknown syntax
  4634. hr = E_ADS_BAD_PARAMETER;
  4635. BAIL_ON_FAILURE(hr);
  4636. }
  4637. error:
  4638. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4639. {
  4640. _fNTDS = FALSE;
  4641. hr = E_NOTIMPL;
  4642. }
  4643. RRETURN_EXP_IF_ERR(hr);
  4644. }
  4645. STDMETHODIMP
  4646. CLDAPProperty::get_MaxRange( THIS_ long FAR *plMaxRange )
  4647. {
  4648. HRESULT hr = S_OK;
  4649. if ( !plMaxRange )
  4650. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4651. if ( !_fNTDS )
  4652. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4653. hr = get_LONG_Property(this, TEXT("rangeUpper"), plMaxRange );
  4654. if ( SUCCEEDED(hr) )
  4655. RRETURN(hr);
  4656. if ( _pPropertyInfo == NULL ) // new class
  4657. {
  4658. hr = E_ADS_PROPERTY_NOT_SET;
  4659. RRETURN_EXP_IF_ERR(hr);
  4660. }
  4661. RRETURN_EXP_IF_ERR(hr);
  4662. }
  4663. STDMETHODIMP
  4664. CLDAPProperty::put_MaxRange( THIS_ long lMaxRange )
  4665. {
  4666. if ( !_fNTDS )
  4667. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4668. HRESULT hr = put_LONG_Property( this, TEXT("rangeUpper"),
  4669. lMaxRange );
  4670. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4671. {
  4672. _fNTDS = FALSE;
  4673. hr = E_NOTIMPL;
  4674. }
  4675. RRETURN_EXP_IF_ERR(hr);
  4676. }
  4677. STDMETHODIMP
  4678. CLDAPProperty::get_MinRange( THIS_ long FAR *plMinRange )
  4679. {
  4680. HRESULT hr = S_OK;
  4681. if ( !plMinRange )
  4682. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4683. if ( !_fNTDS )
  4684. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4685. hr = get_LONG_Property(this, TEXT("rangeLower"), plMinRange );
  4686. if ( SUCCEEDED(hr) )
  4687. RRETURN(hr);
  4688. if ( _pPropertyInfo == NULL ) // new class
  4689. {
  4690. hr = E_ADS_PROPERTY_NOT_SET;
  4691. RRETURN_EXP_IF_ERR(hr);
  4692. }
  4693. RRETURN_EXP_IF_ERR(hr);
  4694. }
  4695. STDMETHODIMP
  4696. CLDAPProperty::put_MinRange( THIS_ long lMinRange )
  4697. {
  4698. if ( !_fNTDS )
  4699. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4700. HRESULT hr = put_LONG_Property( this, TEXT("rangeLower"),
  4701. lMinRange );
  4702. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4703. {
  4704. _fNTDS = FALSE;
  4705. hr = E_NOTIMPL;
  4706. }
  4707. RRETURN_EXP_IF_ERR(hr);
  4708. }
  4709. STDMETHODIMP
  4710. CLDAPProperty::get_MultiValued( THIS_ VARIANT_BOOL FAR *pfMultiValued )
  4711. {
  4712. if ( !pfMultiValued )
  4713. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4714. HRESULT hr = S_OK;
  4715. VARIANT_BOOL fSingleValued = FALSE; // by default
  4716. if ( _fNTDS )
  4717. {
  4718. hr = get_VARIANT_BOOL_Property( this, TEXT("isSingleValued"),
  4719. &fSingleValued );
  4720. BAIL_ON_FAILURE(hr);
  4721. }
  4722. else if ( _pPropertyInfo )
  4723. {
  4724. fSingleValued = (VARIANT_BOOL)_pPropertyInfo->fSingleValued;
  4725. }
  4726. *pfMultiValued = fSingleValued? VARIANT_FALSE : VARIANT_TRUE;
  4727. error:
  4728. RRETURN_EXP_IF_ERR(hr);
  4729. }
  4730. STDMETHODIMP
  4731. CLDAPProperty::put_MultiValued( THIS_ VARIANT_BOOL fMultiValued )
  4732. {
  4733. if ( !_fNTDS )
  4734. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4735. HRESULT hr = put_VARIANT_BOOL_Property( (IADs *) this,
  4736. TEXT("isSingleValued"),
  4737. !fMultiValued );
  4738. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4739. {
  4740. _fNTDS = FALSE;
  4741. hr = E_NOTIMPL;
  4742. }
  4743. RRETURN_EXP_IF_ERR(hr);
  4744. }
  4745. STDMETHODIMP
  4746. CLDAPProperty::Qualifiers(THIS_ IADsCollection FAR* FAR* ppQualifiers)
  4747. {
  4748. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4749. }
  4750. HRESULT
  4751. CLDAPProperty::AllocatePropertyObject(
  4752. CCredentials& Credentials,
  4753. CLDAPProperty FAR * FAR * ppProperty
  4754. )
  4755. {
  4756. CLDAPProperty FAR *pProperty = NULL;
  4757. CAggregatorDispMgr FAR *pDispMgr = NULL;
  4758. CPropertyCache FAR *pPropertyCache = NULL;
  4759. HRESULT hr = S_OK;
  4760. pProperty = new CLDAPProperty();
  4761. if ( pProperty == NULL )
  4762. hr = E_OUTOFMEMORY;
  4763. BAIL_ON_FAILURE(hr);
  4764. pDispMgr = new CAggregatorDispMgr(Credentials);
  4765. if ( pDispMgr == NULL )
  4766. hr = E_OUTOFMEMORY;
  4767. BAIL_ON_FAILURE(hr);
  4768. hr = pDispMgr->LoadTypeInfoEntry(
  4769. LIBID_ADs,
  4770. IID_IADs,
  4771. (IADs *) pProperty,
  4772. DISPID_REGULAR );
  4773. BAIL_ON_FAILURE(hr);
  4774. hr = pDispMgr->LoadTypeInfoEntry(
  4775. LIBID_ADs,
  4776. IID_IADsProperty,
  4777. (IADsProperty *) pProperty,
  4778. DISPID_REGULAR );
  4779. BAIL_ON_FAILURE(hr);
  4780. hr = CPropertyCache::createpropertycache(
  4781. (CCoreADsObject FAR *) pProperty,
  4782. (IGetAttributeSyntax *) pProperty,
  4783. &pPropertyCache
  4784. );
  4785. BAIL_ON_FAILURE(hr);
  4786. pDispMgr->RegisterPropertyCache(pPropertyCache);
  4787. pProperty->_Credentials = Credentials;
  4788. pProperty->_pDispMgr = pDispMgr;
  4789. pProperty->_pPropertyCache = pPropertyCache;
  4790. *ppProperty = pProperty;
  4791. RRETURN(hr);
  4792. error:
  4793. delete pDispMgr;
  4794. delete pProperty;
  4795. RRETURN(hr);
  4796. }
  4797. //
  4798. // Needed for dynamic dispid's in the property cache.
  4799. //
  4800. HRESULT
  4801. CLDAPProperty::GetAttributeSyntax(
  4802. LPWSTR szPropertyName,
  4803. PDWORD pdwSyntaxId
  4804. )
  4805. {
  4806. HRESULT hr;
  4807. hr = LdapGetSyntaxOfAttributeOnServer(
  4808. _pszLDAPServer,
  4809. szPropertyName,
  4810. pdwSyntaxId,
  4811. _Credentials,
  4812. _dwPort
  4813. );
  4814. RRETURN_EXP_IF_ERR(hr);
  4815. }
  4816. /******************************************************************/
  4817. /* Class CLDAPSyntax
  4818. /******************************************************************/
  4819. DEFINE_IDispatch_Implementation(CLDAPSyntax)
  4820. DEFINE_IADs_Implementation(CLDAPSyntax)
  4821. DEFINE_IADsPutGet_UnImplementation(CLDAPSyntax)
  4822. CLDAPSyntax::CLDAPSyntax()
  4823. : _pDispMgr( NULL ),
  4824. _pPropertyCache(NULL)
  4825. {
  4826. ENLIST_TRACKING(CLDAPSyntax);
  4827. }
  4828. CLDAPSyntax::~CLDAPSyntax()
  4829. {
  4830. delete _pDispMgr;
  4831. delete _pPropertyCache;
  4832. }
  4833. HRESULT
  4834. CLDAPSyntax::CreateSyntax(
  4835. BSTR bstrParent,
  4836. SYNTAXINFO *pSyntaxInfo,
  4837. CCredentials& Credentials,
  4838. DWORD dwObjectState,
  4839. REFIID riid,
  4840. void **ppvObj
  4841. )
  4842. {
  4843. CLDAPSyntax FAR *pSyntax = NULL;
  4844. HRESULT hr = S_OK;
  4845. hr = AllocateSyntaxObject(Credentials, &pSyntax );
  4846. BAIL_ON_FAILURE(hr);
  4847. hr = pSyntax->InitializeCoreObject(
  4848. bstrParent,
  4849. pSyntaxInfo->pszName,
  4850. SYNTAX_CLASS_NAME,
  4851. CLSID_LDAPSyntax,
  4852. dwObjectState );
  4853. BAIL_ON_FAILURE(hr);
  4854. pSyntax->_lOleAutoDataType = pSyntaxInfo->lOleAutoDataType;
  4855. //
  4856. // If the call is from umi we need to instantiate the umi object.
  4857. //
  4858. if (Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
  4859. hr = ((CCoreADsObject*)pSyntax)->InitUmiObject(
  4860. IntfPropsSchema,
  4861. pSyntax->_pPropertyCache,
  4862. (IADs *) pSyntax,
  4863. (IADs *) pSyntax,
  4864. riid,
  4865. ppvObj,
  4866. &(pSyntax->_Credentials)
  4867. );
  4868. BAIL_ON_FAILURE(hr);
  4869. //
  4870. // Set the simulated Name property.
  4871. //
  4872. hr = HelperPutStringPropertyInCache(
  4873. L"Name",
  4874. pSyntaxInfo->pszName,
  4875. pSyntax->_Credentials,
  4876. pSyntax->_pPropertyCache
  4877. );
  4878. BAIL_ON_FAILURE(hr);
  4879. RRETURN(S_OK);
  4880. }
  4881. hr = pSyntax->QueryInterface( riid, ppvObj );
  4882. BAIL_ON_FAILURE(hr);
  4883. pSyntax->Release();
  4884. RRETURN(hr);
  4885. error:
  4886. *ppvObj = NULL;
  4887. delete pSyntax;
  4888. RRETURN_EXP_IF_ERR(hr);
  4889. }
  4890. STDMETHODIMP
  4891. CLDAPSyntax::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  4892. {
  4893. if (ppv == NULL) {
  4894. RRETURN(E_POINTER);
  4895. }
  4896. if (IsEqualIID(iid, IID_IUnknown))
  4897. {
  4898. *ppv = (IADs FAR *) this;
  4899. }
  4900. else if (IsEqualIID(iid, IID_IDispatch))
  4901. {
  4902. *ppv = (IADs FAR *) this;
  4903. }
  4904. else if (IsEqualIID(iid, IID_ISupportErrorInfo))
  4905. {
  4906. *ppv = (ISupportErrorInfo FAR *) this;
  4907. }
  4908. else if (IsEqualIID(iid, IID_IADs))
  4909. {
  4910. *ppv = (IADs FAR *) this;
  4911. }
  4912. else if (IsEqualIID(iid, IID_IADsSyntax))
  4913. {
  4914. *ppv = (IADsSyntax FAR *) this;
  4915. }
  4916. else
  4917. {
  4918. *ppv = NULL;
  4919. return E_NOINTERFACE;
  4920. }
  4921. AddRef();
  4922. return NOERROR;
  4923. }
  4924. /* ISupportErrorInfo method */
  4925. STDMETHODIMP
  4926. CLDAPSyntax::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
  4927. {
  4928. if (IsEqualIID(riid, IID_IADs) ||
  4929. IsEqualIID(riid, IID_IADsSyntax)) {
  4930. RRETURN(S_OK);
  4931. } else {
  4932. RRETURN(S_FALSE);
  4933. }
  4934. }
  4935. /* IADs methods */
  4936. STDMETHODIMP
  4937. CLDAPSyntax::SetInfo(THIS)
  4938. {
  4939. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4940. }
  4941. STDMETHODIMP
  4942. CLDAPSyntax::GetInfo(THIS)
  4943. {
  4944. RRETURN(S_OK);
  4945. }
  4946. STDMETHODIMP
  4947. CLDAPSyntax::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
  4948. {
  4949. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4950. }
  4951. HRESULT
  4952. CLDAPSyntax::AllocateSyntaxObject(
  4953. CCredentials& Credentials,
  4954. CLDAPSyntax FAR * FAR * ppSyntax
  4955. )
  4956. {
  4957. CLDAPSyntax FAR *pSyntax = NULL;
  4958. CAggregatorDispMgr FAR *pDispMgr = NULL;
  4959. CPropertyCache FAR *pPropertyCache = NULL;
  4960. HRESULT hr = S_OK;
  4961. pSyntax = new CLDAPSyntax();
  4962. if ( pSyntax == NULL )
  4963. hr = E_OUTOFMEMORY;
  4964. BAIL_ON_FAILURE(hr);
  4965. pDispMgr = new CAggregatorDispMgr(Credentials);
  4966. if ( pDispMgr == NULL )
  4967. hr = E_OUTOFMEMORY;
  4968. BAIL_ON_FAILURE(hr);
  4969. hr = pDispMgr->LoadTypeInfoEntry(
  4970. LIBID_ADs,
  4971. IID_IADsSyntax,
  4972. (IADsSyntax *) pSyntax,
  4973. DISPID_REGULAR );
  4974. BAIL_ON_FAILURE(hr);
  4975. hr = CPropertyCache::createpropertycache(
  4976. (CCoreADsObject FAR *) pSyntax,
  4977. (IGetAttributeSyntax *) pSyntax,
  4978. &pPropertyCache
  4979. );
  4980. BAIL_ON_FAILURE(hr);
  4981. pSyntax->_pPropertyCache = pPropertyCache;
  4982. pSyntax->_Credentials = Credentials;
  4983. pSyntax->_pDispMgr = pDispMgr;
  4984. *ppSyntax = pSyntax;
  4985. RRETURN(hr);
  4986. error:
  4987. delete pDispMgr;
  4988. delete pSyntax;
  4989. delete pPropertyCache;
  4990. RRETURN_EXP_IF_ERR(hr);
  4991. }
  4992. STDMETHODIMP
  4993. CLDAPSyntax::get_OleAutoDataType( THIS_ long FAR *plOleAutoDataType )
  4994. {
  4995. if ( !plOleAutoDataType )
  4996. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4997. *plOleAutoDataType = _lOleAutoDataType;
  4998. RRETURN(S_OK);
  4999. }
  5000. STDMETHODIMP
  5001. CLDAPSyntax::put_OleAutoDataType( THIS_ long lOleAutoDataType )
  5002. {
  5003. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  5004. }
  5005. //
  5006. // Needed for dynamic dispid's in the property cache.
  5007. //
  5008. HRESULT
  5009. CLDAPSyntax::GetAttributeSyntax(
  5010. LPWSTR szPropertyName,
  5011. PDWORD pdwSyntaxId
  5012. )
  5013. {
  5014. HRESULT hr = S_OK;
  5015. if ((_Credentials.GetAuthFlags() & ADS_AUTH_RESERVED)
  5016. && !_wcsicmp(L"Name", szPropertyName)) {
  5017. *pdwSyntaxId = LDAPTYPE_CASEIGNORESTRING;
  5018. }
  5019. else {
  5020. hr = E_ADS_PROPERTY_NOT_FOUND;
  5021. }
  5022. RRETURN_EXP_IF_ERR(hr);
  5023. }
  5024. /******************************************************************/
  5025. /* Misc Helpers
  5026. /******************************************************************/
  5027. HRESULT
  5028. MakeVariantFromStringArray(
  5029. BSTR *bstrList,
  5030. VARIANT *pvVariant
  5031. )
  5032. {
  5033. HRESULT hr = S_OK;
  5034. SAFEARRAY *aList = NULL;
  5035. SAFEARRAYBOUND aBound;
  5036. if ( (bstrList != NULL) && (*bstrList != 0) )
  5037. {
  5038. long i = 0;
  5039. long j = 0;
  5040. long nCount = 0;
  5041. while ( bstrList[nCount] )
  5042. nCount++;
  5043. if ( nCount == 1 )
  5044. {
  5045. VariantInit( pvVariant );
  5046. V_VT(pvVariant) = VT_BSTR;
  5047. hr = ADsAllocString( bstrList[0], &(V_BSTR(pvVariant)));
  5048. RRETURN_EXP_IF_ERR(hr);
  5049. }
  5050. aBound.lLbound = 0;
  5051. aBound.cElements = nCount;
  5052. aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
  5053. if ( aList == NULL )
  5054. {
  5055. hr = E_OUTOFMEMORY;
  5056. BAIL_ON_FAILURE(hr);
  5057. }
  5058. i = 0;
  5059. while ( bstrList[i] )
  5060. {
  5061. VARIANT v;
  5062. VariantInit(&v);
  5063. V_VT(&v) = VT_BSTR;
  5064. hr = ADsAllocString( bstrList[i], &(V_BSTR(&v)));
  5065. BAIL_ON_FAILURE(hr);
  5066. hr = SafeArrayPutElement( aList,
  5067. &i,
  5068. &v );
  5069. VariantClear(&v);
  5070. BAIL_ON_FAILURE(hr);
  5071. i++;
  5072. }
  5073. VariantInit( pvVariant );
  5074. V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
  5075. V_ARRAY(pvVariant) = aList;
  5076. }
  5077. else
  5078. {
  5079. aBound.lLbound = 0;
  5080. aBound.cElements = 0;
  5081. aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
  5082. if ( aList == NULL )
  5083. {
  5084. hr = E_OUTOFMEMORY;
  5085. BAIL_ON_FAILURE(hr);
  5086. }
  5087. VariantInit( pvVariant );
  5088. V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
  5089. V_ARRAY(pvVariant) = aList;
  5090. }
  5091. return S_OK;
  5092. error:
  5093. if ( aList )
  5094. SafeArrayDestroy( aList );
  5095. return hr;
  5096. }
  5097. HRESULT
  5098. MakeVariantFromPropStringTable(
  5099. int *propList,
  5100. LDAP_SCHEMA_HANDLE hSchema,
  5101. VARIANT *pvVariant
  5102. )
  5103. {
  5104. HRESULT hr = S_OK;
  5105. DWORD nCount = 0;
  5106. BSTR *aStrings = NULL;
  5107. if ( propList != NULL )
  5108. {
  5109. while ( propList[nCount] != -1 )
  5110. nCount++;
  5111. }
  5112. if ( nCount > 0 )
  5113. {
  5114. hr = SchemaGetStringsFromStringTable(
  5115. hSchema,
  5116. propList,
  5117. nCount,
  5118. &aStrings );
  5119. if (FAILED(hr))
  5120. RRETURN_EXP_IF_ERR(hr);
  5121. }
  5122. hr = MakeVariantFromStringArray(
  5123. aStrings,
  5124. pvVariant );
  5125. for ( DWORD i = 0; i < nCount; i ++ )
  5126. {
  5127. FreeADsStr( aStrings[i] );
  5128. }
  5129. if (aStrings)
  5130. {
  5131. FreeADsMem( aStrings );
  5132. }
  5133. RRETURN(hr);
  5134. }
  5135. /* No longer needed
  5136. HRESULT
  5137. DeleteSchemaEntry(
  5138. LPTSTR szADsPath,
  5139. LPTSTR szRelativeName,
  5140. LPTSTR szClassName,
  5141. LPTSTR szSubSchemaSubEntry,
  5142. CCredentials& Credentials
  5143. )
  5144. {
  5145. HRESULT hr = S_OK;
  5146. ADS_LDP *ld = NULL;
  5147. TCHAR *pszParentLDAPServer = NULL;
  5148. LPWSTR pszParentLDAPDn = NULL;
  5149. DWORD dwPort = 0;
  5150. LPWSTR pszLDAPDn = NULL;
  5151. LPTSTR *aValues = NULL;
  5152. int nCount = 0;
  5153. //
  5154. // Need to distinguish between LDAP Display Name and ...
  5155. //
  5156. //
  5157. // Get the LDAP server name
  5158. //
  5159. hr = BuildLDAPPathFromADsPath2(
  5160. szADsPath,
  5161. &pszParentLDAPServer,
  5162. &pszParentLDAPDn,
  5163. &dwPort
  5164. );
  5165. BAIL_ON_FAILURE(hr);
  5166. if ( szSubSchemaSubEntry == NULL ) // not NTDS
  5167. {
  5168. hr = E_NOTIMPL;
  5169. BAIL_ON_FAILURE(hr);
  5170. }
  5171. //
  5172. // Get the name of the schema object
  5173. //
  5174. pszLDAPDn = (LPTSTR) AllocADsMem((_tcslen(szRelativeName )
  5175. + _tcslen( _tcschr(szSubSchemaSubEntry,TEXT(',')))
  5176. ) * sizeof(TCHAR)); // includes "\\"
  5177. if ( pszLDAPDn == NULL ){
  5178. hr = E_OUTOFMEMORY;
  5179. BAIL_ON_FAILURE(hr);
  5180. }
  5181. _tcscpy( pszLDAPDn, szRelativeName );
  5182. _tcscat( pszLDAPDn, _tcschr( szSubSchemaSubEntry, TEXT(',')) );
  5183. if ( aValues )
  5184. {
  5185. LdapValueFree( aValues );
  5186. aValues = NULL;
  5187. nCount = 0;
  5188. }
  5189. //
  5190. // Validate the class name first
  5191. //
  5192. hr = LdapReadAttribute(
  5193. pszParentLDAPServer,
  5194. pszLDAPDn,
  5195. TEXT("objectClass"),
  5196. &aValues,
  5197. &nCount,
  5198. Credentials,
  5199. dwPort
  5200. );
  5201. BAIL_ON_FAILURE(hr);
  5202. if ( nCount > 0 )
  5203. {
  5204. if ( _tcsicmp( szClassName, GET_BASE_CLASS( aValues, nCount) ) != 0 )
  5205. {
  5206. hr = E_ADS_BAD_PARAMETER;
  5207. BAIL_ON_FAILURE(hr);
  5208. }
  5209. }
  5210. //
  5211. // Class name has been verified, so delete the object
  5212. //
  5213. hr = LdapDeleteS(
  5214. ld,
  5215. pszLDAPDn
  5216. );
  5217. BAIL_ON_FAILURE(hr);
  5218. error:
  5219. if (pszParentLDAPServer) {
  5220. FreeADsStr(pszParentLDAPServer);
  5221. }
  5222. if (pszParentLDAPDn) {
  5223. FreeADsStr(pszParentLDAPDn);
  5224. }
  5225. if (pszLDAPDn) {
  5226. FreeADsStr(pszLDAPDn);
  5227. }
  5228. if ( aValues ) {
  5229. LdapValueFree( aValues );
  5230. }
  5231. if ( ld ) {
  5232. LdapCloseObject( ld );
  5233. }
  5234. RRETURN(hr);
  5235. }
  5236. */
  5237. //
  5238. // ******** Important usage note **********
  5239. // Users of this function must make sure that cn is part of
  5240. // the list of attributes passed in. This is a requirement and
  5241. // the array must contain a NULL string as the last element.
  5242. // ******** Important usage note **********
  5243. //
  5244. HRESULT
  5245. BuildSchemaLDAPPathAndGetAttribute(
  5246. IN LPTSTR pszParent,
  5247. IN LPTSTR pszName,
  5248. IN LPTSTR pszSubSchemaSubEntry,
  5249. IN BOOL fNew,
  5250. IN CCredentials& Credentials,
  5251. IN LPTSTR pszAttribs[],
  5252. OUT LPWSTR * ppszSchemaLDAPServer,
  5253. OUT LPWSTR * ppszSchemaLDAPDn,
  5254. IN OUT PADS_LDP *ppLd, // optional in,
  5255. OUT PLDAPMessage *ppRes // caller need to get first entry
  5256. )
  5257. {
  5258. HRESULT hr = S_OK;
  5259. LPTSTR pszLDAPServer = NULL;
  5260. LPWSTR pszLDAPDn = NULL;
  5261. DWORD dwPort = 0;
  5262. BOOL fOpenLd = FALSE;
  5263. LPTSTR pszSchemaRoot = NULL;
  5264. TCHAR szFilter[MAX_PATH] = BEGIN_FILTER; // name on ldap svr
  5265. LDAPMessage *pE = NULL;
  5266. int nCount = 0;
  5267. LPTSTR pszClassName = NULL;
  5268. LPTSTR *aValues = NULL;
  5269. int nNumberOfEntries = 0;
  5270. if ( !ppszSchemaLDAPServer || !ppszSchemaLDAPDn || !ppLd || !ppRes)
  5271. {
  5272. RRETURN(E_ADS_BAD_PARAMETER);
  5273. }
  5274. //
  5275. // Using pszSubSchemaSubEntry to test NTDS is no longer accurate.
  5276. // But the following codes are written to work for NTDS.
  5277. //
  5278. if ( pszSubSchemaSubEntry == NULL ) // not NTDS
  5279. {
  5280. hr = E_NOTIMPL;
  5281. BAIL_IF_ERROR(hr);
  5282. }
  5283. //
  5284. // Get the server name & port #
  5285. //
  5286. hr = BuildLDAPPathFromADsPath2(
  5287. pszParent,
  5288. &pszLDAPServer,
  5289. &pszLDAPDn,
  5290. &dwPort
  5291. );
  5292. BAIL_IF_ERROR(hr);
  5293. //
  5294. // Connect and bind to schema Root object (in NTDS only)
  5295. //
  5296. pszSchemaRoot = _tcschr( // strip CN=Aggregate
  5297. pszSubSchemaSubEntry,
  5298. TEXT(',')
  5299. );
  5300. if ( *ppLd == NULL )
  5301. {
  5302. hr = LdapOpenObject(
  5303. pszLDAPServer,
  5304. pszSchemaRoot+1, // go past ",", we've stripped CN=Aggregate
  5305. ppLd,
  5306. Credentials,
  5307. dwPort
  5308. );
  5309. BAIL_IF_ERROR(hr);
  5310. fOpenLd = TRUE;
  5311. }
  5312. //
  5313. // Set Serach Filter to (& (lDAPDisplayName=<pszName>)
  5314. // (! (isDefunct=TRUE) )
  5315. // )
  5316. //
  5317. _tcscat( szFilter, pszName );
  5318. _tcscat( szFilter, END_FILTER );
  5319. //
  5320. // Search for scheam pszName (class object) under schema root
  5321. //
  5322. hr = LdapSearchS(
  5323. *ppLd,
  5324. pszSchemaRoot+1, // go past ",", we've stripped CN=Aggregate
  5325. LDAP_SCOPE_ONELEVEL,
  5326. szFilter,
  5327. pszAttribs,
  5328. 0,
  5329. ppRes
  5330. );
  5331. //
  5332. // Confirm with anoopa & johnsona (ntds5) :
  5333. // If 1 out of the 2 attributes asked for is not on the svr,
  5334. // LdapSearchS (ldap_search_s) returns the 1 located and hr = S_OK
  5335. //
  5336. BAIL_IF_ERROR(hr);
  5337. //
  5338. // Only one active entry should be returned.
  5339. // If more than one entry is returned, return E_ADS_SCHEMA_VIOLATION
  5340. // Get cn to build schemalLDAPDn
  5341. //
  5342. nNumberOfEntries = LdapCountEntries( *ppLd, *ppRes );
  5343. if ( nNumberOfEntries != 1 )
  5344. RRETURN(E_ADS_SCHEMA_VIOLATION);
  5345. if ( fNew) // ? still keep this
  5346. {
  5347. pszClassName = pszName;
  5348. }
  5349. else
  5350. {
  5351. hr = LdapFirstEntry(
  5352. *ppLd,
  5353. *ppRes,
  5354. &pE
  5355. );
  5356. BAIL_IF_ERROR(hr);
  5357. hr = LdapGetValues(
  5358. *ppLd,
  5359. pE,
  5360. L"cn",
  5361. &aValues,
  5362. &nCount
  5363. );
  5364. BAIL_IF_ERROR(hr);
  5365. if (nCount == 0)
  5366. {
  5367. // use lDAPDisplayName as common name (cn) if cn not set on svr
  5368. pszClassName = pszName;
  5369. }
  5370. else
  5371. {
  5372. pszClassName = aValues[0];
  5373. }
  5374. }
  5375. if (pszLDAPServer!=NULL)
  5376. {
  5377. *ppszSchemaLDAPServer = (LPWSTR) AllocADsStr(
  5378. pszLDAPServer
  5379. );
  5380. if (*ppszSchemaLDAPServer == NULL)
  5381. {
  5382. hr = E_OUTOFMEMORY;
  5383. BAIL_IF_ERROR(hr);
  5384. }
  5385. }
  5386. else // pszLDAPServer allowed to be NULL
  5387. {
  5388. *ppszSchemaLDAPServer = NULL;
  5389. }
  5390. *ppszSchemaLDAPDn = (LPWSTR) AllocADsMem(
  5391. (_tcslen(L"CN=") +
  5392. _tcslen(pszClassName) +
  5393. _tcslen(pszSchemaRoot) + 1 ) *
  5394. sizeof(TCHAR)
  5395. );
  5396. if ( *ppszSchemaLDAPDn == NULL )
  5397. {
  5398. hr = E_OUTOFMEMORY;
  5399. BAIL_IF_ERROR(hr);
  5400. }
  5401. _tcscpy( *ppszSchemaLDAPDn, L"CN=");
  5402. _tcscat( *ppszSchemaLDAPDn, pszClassName );
  5403. _tcscat( *ppszSchemaLDAPDn, pszSchemaRoot );
  5404. //
  5405. // clean up for both success and failure
  5406. //
  5407. if ( pszLDAPServer )
  5408. FreeADsStr( pszLDAPServer );
  5409. if (pszLDAPDn) {
  5410. FreeADsMem( pszLDAPDn );
  5411. }
  5412. if ( aValues )
  5413. LdapValueFree( aValues );
  5414. RRETURN(hr);
  5415. cleanup:
  5416. //
  5417. // clean up if failure only
  5418. //
  5419. if (fOpenLd==TRUE) {
  5420. LdapCloseObject(*ppLd);
  5421. *ppLd= NULL;
  5422. }
  5423. if (*ppRes) {
  5424. LdapMsgFree(*ppRes);
  5425. *ppRes=NULL;
  5426. }
  5427. if (*ppszSchemaLDAPServer) {
  5428. FreeADsStr(*ppszSchemaLDAPServer);
  5429. *ppszSchemaLDAPServer=NULL;
  5430. }
  5431. if (*ppszSchemaLDAPDn) {
  5432. FreeADsMem(*ppszSchemaLDAPDn);
  5433. *ppszSchemaLDAPDn=NULL;
  5434. }
  5435. RRETURN(hr);
  5436. }
  5437. HRESULT
  5438. BuildSchemaLDAPPath(
  5439. LPTSTR pszParent,
  5440. LPTSTR pszName,
  5441. LPTSTR pszSubSchemaSubEntry,
  5442. LPWSTR * ppszSchemaLDAPServer,
  5443. LPWSTR * ppszSchemaLDAPDn,
  5444. BOOL fNew,
  5445. ADS_LDP **pld,
  5446. CCredentials& Credentials
  5447. )
  5448. {
  5449. HRESULT hr = S_OK;
  5450. LPTSTR *aValues = NULL;
  5451. LPTSTR *aValues2 = NULL;
  5452. int nCount = 0;
  5453. TCHAR szFilter[MAX_PATH] = TEXT("lDAPDisplayName=");
  5454. LPTSTR aStrings[2];
  5455. LDAPMessage *res = NULL;
  5456. LDAPMessage *e = NULL;
  5457. LPTSTR pszLDAPServer = NULL;
  5458. LPWSTR pszLDAPDn = NULL;
  5459. DWORD dwPort = 0;
  5460. LPTSTR pszSchemaRoot = NULL;
  5461. LPTSTR pszClassName = NULL;
  5462. //
  5463. // Get the server name
  5464. //
  5465. hr = BuildLDAPPathFromADsPath2(
  5466. pszParent,
  5467. &pszLDAPServer,
  5468. &pszLDAPDn,
  5469. &dwPort
  5470. );
  5471. BAIL_IF_ERROR(hr);
  5472. if ( pszSubSchemaSubEntry == NULL ) // not NTDS
  5473. {
  5474. hr = E_NOTIMPL;
  5475. BAIL_IF_ERROR(hr);
  5476. }
  5477. // the _tcschr is to get rid of "CN=Aggregate"
  5478. pszSchemaRoot = _tcschr(pszSubSchemaSubEntry, TEXT(','));
  5479. if ( fNew )
  5480. {
  5481. pszClassName = pszName;
  5482. }
  5483. else
  5484. {
  5485. _tcscat( szFilter, pszName );
  5486. aStrings[0] = TEXT("cn");
  5487. aStrings[1] = NULL;
  5488. if ( *pld == NULL )
  5489. {
  5490. hr = LdapOpenObject(
  5491. pszLDAPServer,
  5492. pszSchemaRoot + 1, // go past the , - we've stripped off "CN=Aggregate"
  5493. pld,
  5494. Credentials,
  5495. dwPort
  5496. );
  5497. BAIL_IF_ERROR(hr);
  5498. }
  5499. hr = LdapSearchS(
  5500. *pld,
  5501. pszSchemaRoot + 1,
  5502. LDAP_SCOPE_ONELEVEL,
  5503. szFilter,
  5504. aStrings,
  5505. 0,
  5506. &res
  5507. );
  5508. // Only one entry should be returned
  5509. if (FAILED(hr)
  5510. || (FAILED(hr = LdapFirstEntry( *pld, res, &e )))
  5511. || (FAILED(hr = LdapGetValues( *pld, e, aStrings[0], &aValues2, &nCount)))
  5512. )
  5513. {
  5514. BAIL_IF_ERROR(hr);
  5515. }
  5516. if ( nCount == 0 )
  5517. pszClassName = pszName;
  5518. else
  5519. pszClassName = aValues2[0];
  5520. }
  5521. *ppszSchemaLDAPServer = (LPWSTR)AllocADsStr(pszLDAPServer);
  5522. //
  5523. // pszLDAPServer might be NULL, in which case NULL is the
  5524. // expected return value from the alloc.
  5525. //
  5526. if ( (*ppszSchemaLDAPServer == NULL) && pszLDAPServer) {
  5527. hr = E_OUTOFMEMORY;
  5528. BAIL_IF_ERROR(hr);
  5529. }
  5530. *ppszSchemaLDAPDn = (LPTSTR) AllocADsMem(
  5531. (_tcslen(L"CN=") +
  5532. _tcslen(pszClassName) +
  5533. _tcslen(pszSchemaRoot) + 1 ) *
  5534. sizeof(TCHAR));
  5535. if ( *ppszSchemaLDAPDn == NULL )
  5536. {
  5537. hr = E_OUTOFMEMORY;
  5538. BAIL_IF_ERROR(hr);
  5539. }
  5540. _tcscpy( *ppszSchemaLDAPDn, L"CN=");
  5541. _tcscat( *ppszSchemaLDAPDn, pszClassName );
  5542. _tcscat( *ppszSchemaLDAPDn, pszSchemaRoot );
  5543. cleanup:
  5544. if ( aValues )
  5545. LdapValueFree( aValues );
  5546. if ( aValues2 )
  5547. LdapValueFree( aValues2 );
  5548. if ( pszLDAPServer )
  5549. FreeADsStr( pszLDAPServer );
  5550. if (pszLDAPDn) {
  5551. FreeADsStr( pszLDAPDn);
  5552. }
  5553. if ( res )
  5554. LdapMsgFree( res );
  5555. RRETURN(hr);
  5556. }
  5557. HRESULT
  5558. MakePropArrayFromVariant(
  5559. VARIANT vProp,
  5560. SCHEMAINFO *hSchema,
  5561. int **pOIDs,
  5562. DWORD *pnNumOfOids )
  5563. {
  5564. HRESULT hr = S_OK;
  5565. int nIndex;
  5566. LONG dwSLBound;
  5567. LONG dwSUBound;
  5568. LONG i = 0;
  5569. LONG j, k;
  5570. DWORD nCurrent = 0;
  5571. *pOIDs = NULL;
  5572. *pnNumOfOids = 0;
  5573. if ( !V_ISARRAY( &vProp))
  5574. {
  5575. // special case of one object (not an array)
  5576. nIndex = FindSearchTableIndex( V_BSTR(&vProp),
  5577. hSchema->aPropertiesSearchTable,
  5578. hSchema->nNumOfProperties * 2 );
  5579. if ( nIndex != -1 )
  5580. {
  5581. *pOIDs = (int *) AllocADsMem( sizeof(int) * 2);
  5582. if ( *pOIDs == NULL )
  5583. {
  5584. hr = E_OUTOFMEMORY;
  5585. BAIL_ON_FAILURE(hr);
  5586. }
  5587. (*pOIDs)[nCurrent++] = nIndex;
  5588. (*pOIDs)[nCurrent] = -1;
  5589. *pnNumOfOids = 1;
  5590. }
  5591. else
  5592. {
  5593. hr = E_ADS_PROPERTY_NOT_FOUND;
  5594. }
  5595. RRETURN_EXP_IF_ERR(hr);
  5596. }
  5597. //
  5598. // Here, we have an array of properties. We want to create an array of
  5599. // indexes into the aPropertiesSearchTable
  5600. //
  5601. hr = SafeArrayGetLBound(V_ARRAY(&vProp),
  5602. 1,
  5603. (long FAR *)&dwSLBound
  5604. );
  5605. BAIL_ON_FAILURE(hr);
  5606. hr = SafeArrayGetUBound(V_ARRAY(&vProp),
  5607. 1,
  5608. (long FAR *)&dwSUBound
  5609. );
  5610. BAIL_ON_FAILURE(hr);
  5611. *pOIDs = (int *) AllocADsMem( sizeof(int) * (dwSUBound - dwSLBound + 2));
  5612. if ( *pOIDs == NULL )
  5613. {
  5614. hr = E_OUTOFMEMORY;
  5615. BAIL_ON_FAILURE(hr);
  5616. }
  5617. for (i = dwSLBound; i <= dwSUBound; i++) {
  5618. VARIANT v;
  5619. VariantInit(&v);
  5620. hr = SafeArrayGetElement(V_ARRAY(&vProp),
  5621. (long FAR *)&i,
  5622. &v
  5623. );
  5624. BAIL_ON_FAILURE(hr);
  5625. nIndex = FindSearchTableIndex( V_BSTR(&v),
  5626. hSchema->aPropertiesSearchTable,
  5627. hSchema->nNumOfProperties * 2 );
  5628. VariantClear(&v);
  5629. if ( nIndex != -1 )
  5630. {
  5631. (*pOIDs)[nCurrent++] = nIndex;
  5632. }
  5633. else
  5634. {
  5635. hr = E_ADS_PROPERTY_NOT_FOUND;
  5636. BAIL_ON_FAILURE(hr);
  5637. }
  5638. }
  5639. (*pOIDs)[nCurrent] = -1;
  5640. *pnNumOfOids = nCurrent;
  5641. SortAndRemoveDuplicateOIDs( *pOIDs, pnNumOfOids );
  5642. error:
  5643. if (FAILED(hr))
  5644. {
  5645. if ( *pOIDs )
  5646. {
  5647. FreeADsMem( *pOIDs );
  5648. *pOIDs = NULL;
  5649. }
  5650. }
  5651. RRETURN(hr);
  5652. }
  5653. HRESULT
  5654. MakePropArrayFromStringArray(
  5655. LPTSTR *aValues,
  5656. DWORD nCount,
  5657. SCHEMAINFO *hSchema,
  5658. int **pOIDs,
  5659. DWORD *pnNumOfOids
  5660. )
  5661. {
  5662. HRESULT hr = S_OK;
  5663. int nIndex;
  5664. DWORD i = 0;
  5665. DWORD nCurrent = 0;
  5666. *pOIDs = NULL;
  5667. *pnNumOfOids = 0;
  5668. //
  5669. // Here, we have an array of properties. We want to create an array of
  5670. // indexes into the aPropertiesSearchTable
  5671. //
  5672. *pOIDs = (int *) AllocADsMem( sizeof(int) * (nCount+1));
  5673. if ( *pOIDs == NULL )
  5674. {
  5675. hr = E_OUTOFMEMORY;
  5676. BAIL_ON_FAILURE(hr);
  5677. }
  5678. for (i = 0; i < nCount ; i++) {
  5679. nIndex = FindSearchTableIndex( aValues[i],
  5680. hSchema->aPropertiesSearchTable,
  5681. hSchema->nNumOfProperties * 2 );
  5682. if ( nIndex != -1 )
  5683. {
  5684. (*pOIDs)[nCurrent++] = nIndex;
  5685. }
  5686. else
  5687. {
  5688. hr = E_ADS_PROPERTY_NOT_FOUND;
  5689. BAIL_ON_FAILURE(hr);
  5690. }
  5691. }
  5692. (*pOIDs)[nCurrent] = -1;
  5693. *pnNumOfOids = nCurrent;
  5694. qsort( *pOIDs, *pnNumOfOids, sizeof((*pOIDs)[0]), intcmp );
  5695. error:
  5696. if (FAILED(hr))
  5697. {
  5698. if ( *pOIDs )
  5699. {
  5700. FreeADsMem( *pOIDs );
  5701. *pOIDs = NULL;
  5702. }
  5703. }
  5704. RRETURN(hr);
  5705. }
  5706. /******************************************************************/
  5707. /* Misc Schema functions
  5708. /******************************************************************/
  5709. BOOL
  5710. GetLdapClassPrimaryInterface(
  5711. LPTSTR pszLdapClass,
  5712. GUID **ppPrimaryInterfaceGUID,
  5713. GUID **ppCLSID
  5714. )
  5715. {
  5716. for ( int i = 0; i < ARRAY_SIZE(aClassMap); i++ )
  5717. {
  5718. if ( _tcsicmp( pszLdapClass, aClassMap[i].pszLdapClassName ) == 0 )
  5719. {
  5720. *ppPrimaryInterfaceGUID = (GUID *) aClassMap[i].pPrimaryInterfaceGUID;
  5721. *ppCLSID = (GUID *) aClassMap[i].pCLSID;
  5722. return TRUE;
  5723. }
  5724. }
  5725. return FALSE;
  5726. }
  5727. BOOL
  5728. GetPrimaryInterface(
  5729. LPTSTR pszClassName,
  5730. SCHEMAINFO *pSchemaInfo,
  5731. PCLASSNAME_LIST pClassNames,
  5732. GUID **ppPrimaryInterfaceGUID,
  5733. GUID **ppCLSID
  5734. )
  5735. {
  5736. int i = 0;
  5737. CLASSINFO *pClassInfo;
  5738. LPTSTR pszName;
  5739. DWORD index;
  5740. PCLASSNAME_LIST pClass = NULL;
  5741. PCLASSNAME_LIST pNextClass = NULL;
  5742. BOOL fExitStatus = FALSE;
  5743. if ( GetLdapClassPrimaryInterface( pszClassName,
  5744. ppPrimaryInterfaceGUID,
  5745. ppCLSID ))
  5746. {
  5747. return TRUE;
  5748. }
  5749. index = (DWORD) FindEntryInSearchTable(
  5750. pszClassName,
  5751. pSchemaInfo->aClassesSearchTable,
  5752. 2 * pSchemaInfo->nNumOfClasses );
  5753. if ( index == ((DWORD) -1) )
  5754. return FALSE;
  5755. //
  5756. // Recursively search the list of superiors and
  5757. // aux classes. To avoid loops, we maintain a list
  5758. // of classes we have already reached. If we are called
  5759. // with a class on this list, we abort.
  5760. //
  5761. //
  5762. // Make sure the current class isn't already on the list
  5763. //
  5764. if (pClassNames) {
  5765. for (pNextClass = pClassNames;
  5766. pNextClass != NULL;
  5767. pNextClass = pNextClass->pNext)
  5768. {
  5769. if (_tcscmp(pNextClass->pszClassName, pszClassName) == 0)
  5770. {
  5771. // found match, bail
  5772. fExitStatus = FALSE;
  5773. BAIL_ON_SUCCESS(S_OK);
  5774. }
  5775. }
  5776. }
  5777. //
  5778. // Construct a node for the current class & add it to the list
  5779. //
  5780. pClass = static_cast<PCLASSNAME_LIST>(AllocADsMem(sizeof(CLASSNAME_LIST)));
  5781. if (!pClass) {
  5782. BAIL_ON_FAILURE(E_OUTOFMEMORY);
  5783. }
  5784. pClass->pszClassName = static_cast<LPTSTR>(AllocADsMem((_tcslen(pszClassName)+1) * sizeof(TCHAR)));
  5785. if (!pClass->pszClassName) {
  5786. BAIL_ON_FAILURE(E_OUTOFMEMORY);
  5787. }
  5788. _tcscpy(pClass->pszClassName, pszClassName);
  5789. pClass->pNext = pClassNames;
  5790. //
  5791. // Perform the recursive search
  5792. //
  5793. pClassInfo = &(pSchemaInfo->aClasses[index]);
  5794. if ( pClassInfo->pOIDsSuperiorClasses )
  5795. {
  5796. for ( i = 0;
  5797. (pszName = pClassInfo->pOIDsSuperiorClasses[i]);
  5798. i++ )
  5799. {
  5800. if ( GetPrimaryInterface( pszName, pSchemaInfo, pClass,
  5801. ppPrimaryInterfaceGUID, ppCLSID ))
  5802. {
  5803. fExitStatus = TRUE;
  5804. BAIL_ON_SUCCESS(S_OK);
  5805. }
  5806. }
  5807. }
  5808. if ( pClassInfo->pOIDsAuxClasses )
  5809. {
  5810. for ( i = 0;
  5811. (pszName = pClassInfo->pOIDsAuxClasses[i]);
  5812. i++ )
  5813. {
  5814. if ( GetPrimaryInterface( pszName, pSchemaInfo, pClass,
  5815. ppPrimaryInterfaceGUID, ppCLSID ))
  5816. {
  5817. fExitStatus = TRUE;
  5818. BAIL_ON_SUCCESS(S_OK);
  5819. }
  5820. }
  5821. }
  5822. error:
  5823. //
  5824. // Each level of recursion is responsible for freeing
  5825. // its own corresponding node.
  5826. //
  5827. if (pClass) {
  5828. if (pClass->pszClassName) {
  5829. FreeADsMem(pClass->pszClassName);
  5830. }
  5831. FreeADsMem(pClass);
  5832. }
  5833. return fExitStatus;
  5834. }
  5835. HRESULT
  5836. SchemaGetPrimaryInterface(
  5837. LDAP_SCHEMA_HANDLE hSchema,
  5838. LPTSTR pszClassName,
  5839. GUID **ppPrimaryInterfaceGUID,
  5840. GUID **ppCLSID
  5841. )
  5842. {
  5843. HRESULT hr = S_OK;
  5844. SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
  5845. if ( !pSchemaInfo )
  5846. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  5847. GetPrimaryInterface(
  5848. pszClassName,
  5849. pSchemaInfo,
  5850. NULL,
  5851. ppPrimaryInterfaceGUID,
  5852. ppCLSID );
  5853. RRETURN(hr);
  5854. }
  5855. BOOL
  5856. MapLdapClassToADsClass(
  5857. LPTSTR *aLdapClasses,
  5858. int nCount,
  5859. LPTSTR pszADsClass
  5860. )
  5861. {
  5862. *pszADsClass = 0;
  5863. if ( nCount == 0 )
  5864. return FALSE;
  5865. if ( _tcsicmp( aLdapClasses[nCount-1], TEXT("Top")) == 0 )
  5866. {
  5867. for ( int j = 0; j < nCount; j++ )
  5868. {
  5869. LPTSTR pszLdapClass = aLdapClasses[j];
  5870. for ( int i = 0; i < ARRAY_SIZE(aClassMap); i++ )
  5871. {
  5872. if ( _tcsicmp( pszLdapClass, aClassMap[i].pszLdapClassName ) == 0 )
  5873. {
  5874. _tcscpy( pszADsClass, aClassMap[i].pszADsClassName );
  5875. return TRUE;
  5876. }
  5877. }
  5878. }
  5879. _tcscpy( pszADsClass, aLdapClasses[0] );
  5880. return FALSE;
  5881. }
  5882. else
  5883. {
  5884. for ( int j = nCount-1; j >= 0; j-- )
  5885. {
  5886. LPTSTR pszLdapClass = aLdapClasses[j];
  5887. for ( int i = 0; i < ARRAY_SIZE(aClassMap); i++ )
  5888. {
  5889. if ( _tcsicmp( pszLdapClass, aClassMap[i].pszLdapClassName ) == 0 )
  5890. {
  5891. _tcscpy( pszADsClass, aClassMap[i].pszADsClassName );
  5892. return TRUE;
  5893. }
  5894. }
  5895. }
  5896. _tcscpy( pszADsClass, aLdapClasses[nCount-1] );
  5897. return FALSE;
  5898. }
  5899. }
  5900. BOOL
  5901. MapLdapClassToADsClass(
  5902. LPTSTR pszClassName,
  5903. LDAP_SCHEMA_HANDLE hSchema,
  5904. LPTSTR pszADsClass
  5905. )
  5906. {
  5907. LPTSTR aClasses[1];
  5908. CLASSINFO *pClassInfo = NULL;
  5909. SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
  5910. *pszADsClass = 0;
  5911. aClasses[0] = pszClassName;
  5912. if ( MapLdapClassToADsClass( aClasses, 1, pszADsClass ))
  5913. return TRUE;
  5914. DWORD index = (DWORD) FindEntryInSearchTable(
  5915. pszClassName,
  5916. pSchemaInfo->aClassesSearchTable,
  5917. 2 * pSchemaInfo->nNumOfClasses );
  5918. if ( index == ((DWORD) -1) ) // cannot find the class name in the schema
  5919. {
  5920. _tcscpy( pszADsClass, pszClassName );
  5921. return FALSE;
  5922. }
  5923. pClassInfo = &(pSchemaInfo->aClasses[index]);
  5924. if ( pClassInfo->pOIDsSuperiorClasses )
  5925. {
  5926. LPTSTR pszName = NULL;
  5927. for ( int i = 0;
  5928. (pszName = pClassInfo->pOIDsSuperiorClasses[i]);
  5929. i++ )
  5930. {
  5931. if ( MapLdapClassToADsClass( pszName, pSchemaInfo, pszADsClass))
  5932. return TRUE;
  5933. }
  5934. }
  5935. _tcscpy( pszADsClass, pszClassName );
  5936. return FALSE;
  5937. }
  5938. LPTSTR
  5939. MapADsClassToLdapClass(
  5940. LPTSTR pszADsClass,
  5941. LPTSTR pszLdapClass
  5942. )
  5943. {
  5944. for ( int i=0; i < ARRAY_SIZE(aClassMap); i++ )
  5945. {
  5946. if ( _tcsicmp( pszADsClass, aClassMap[i].pszADsClassName ) == 0 )
  5947. {
  5948. _tcscpy( pszLdapClass, aClassMap[i].pszLdapClassName );
  5949. return pszLdapClass;
  5950. }
  5951. }
  5952. _tcscpy( pszLdapClass, pszADsClass );
  5953. return pszLdapClass;
  5954. }
  5955. STDMETHODIMP
  5956. makeUnionVariantFromLdapObjects(
  5957. LDAPOBJECTARRAY ldapSrcObjects1,
  5958. LDAPOBJECTARRAY ldapSrcObjects2,
  5959. VARIANT FAR * pvPossSuperiors
  5960. )
  5961. {
  5962. HRESULT hr = S_OK;
  5963. BSTR *retVals = NULL;
  5964. DWORD dwNumVals = 0;
  5965. BSTR curString = NULL;
  5966. DWORD dwMaxVals = 0;
  5967. DWORD dwCtr = 0;
  5968. DWORD dwArrIndx = 0;
  5969. PLDAPOBJECT pLdapObject;
  5970. dwMaxVals = ldapSrcObjects1.dwCount + ldapSrcObjects2.dwCount + 1;
  5971. retVals = (BSTR *)AllocADsMem(dwMaxVals * sizeof(BSTR *));
  5972. if (!retVals) {
  5973. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  5974. }
  5975. for (dwCtr = 0; dwCtr < ldapSrcObjects1.dwCount; dwCtr++) {
  5976. pLdapObject = ldapSrcObjects1.pLdapObjects + dwCtr;
  5977. curString = LDAPOBJECT_STRING(pLdapObject);
  5978. hr = addStringIfAbsent(curString, retVals, &dwArrIndx);
  5979. BAIL_ON_FAILURE(hr);
  5980. }
  5981. for (dwCtr = 0; dwCtr < ldapSrcObjects2.dwCount; dwCtr++) {
  5982. pLdapObject = ldapSrcObjects2.pLdapObjects + dwCtr;
  5983. curString = LDAPOBJECT_STRING(pLdapObject);
  5984. hr = addStringIfAbsent(curString, retVals, &dwArrIndx);
  5985. BAIL_ON_FAILURE(hr);
  5986. }
  5987. // do the same for the second ldapobjectarray
  5988. hr = MakeVariantFromStringArray(retVals, pvPossSuperiors);
  5989. error:
  5990. // clean up the string array either way
  5991. for (dwCtr=0; dwCtr < dwArrIndx; dwCtr++) {
  5992. ADsFreeString(retVals[dwCtr]);
  5993. }
  5994. FreeADsMem(retVals);
  5995. RRETURN(hr);
  5996. }
  5997. STDMETHODIMP
  5998. addStringIfAbsent(
  5999. BSTR addString,
  6000. BSTR *strArray,
  6001. PDWORD dwArrIndx
  6002. )
  6003. {
  6004. HRESULT hr = S_OK;
  6005. DWORD dwCtr = 0;
  6006. BOOLEAN fFound = FALSE;
  6007. for (dwCtr = 0; (dwCtr < *dwArrIndx) && !fFound; dwCtr ++) {
  6008. if (!_wcsicmp(addString, strArray[dwCtr])) {
  6009. fFound = TRUE;
  6010. }
  6011. }
  6012. if (!fFound) {
  6013. hr = ADsAllocString(
  6014. addString,
  6015. &strArray[*dwArrIndx]
  6016. );
  6017. BAIL_ON_FAILURE(hr);
  6018. (*dwArrIndx)++;
  6019. strArray[*dwArrIndx] = NULL;
  6020. }
  6021. error:
  6022. RRETURN(hr);
  6023. }