Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7467 lines
181 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. LPTSTR *pTemp = NULL;
  2810. DWORD nValuesAdd = 0;
  2811. DWORD nValuesAddTotal = 10;
  2812. LPTSTR *aValuesRemove = NULL;
  2813. DWORD nValuesRemove = 0;
  2814. DWORD nValuesRemoveTotal = 10;
  2815. DWORD nIndex = 0;
  2816. LDAPMessage *res = NULL;
  2817. LDAPMessage *e = NULL;
  2818. LPTSTR aStrings[] = {
  2819. TEXT("cn"),
  2820. pszPropName,
  2821. NULL
  2822. };
  2823. aValuesAdd = (LPTSTR *) AllocADsMem(sizeof(LPTSTR) * nValuesAddTotal );
  2824. if ( aValuesAdd == NULL )
  2825. {
  2826. hr = E_OUTOFMEMORY;
  2827. BAIL_ON_FAILURE(hr);
  2828. }
  2829. aValuesRemove = (LPTSTR *) AllocADsMem(sizeof(LPTSTR) * nValuesRemoveTotal);
  2830. if ( aValuesRemove == NULL )
  2831. {
  2832. hr = E_OUTOFMEMORY;
  2833. BAIL_ON_FAILURE(hr);
  2834. }
  2835. //
  2836. // We need to find the differences between the properties that needs to be
  2837. // set and the properties that is currently on the server.
  2838. //
  2839. while ((pOIDs[j] != -1) || (pOIDsOld[k] != -1))
  2840. {
  2841. if ( pOIDs[j] == pOIDsOld[k] )
  2842. {
  2843. // No changes here
  2844. j++; k++;
  2845. }
  2846. else if ( ( pOIDsOld[k] == -1 )
  2847. || ( ( pOIDs[j] != -1 ) && ( pOIDs[j] < pOIDsOld[k] ))
  2848. )
  2849. {
  2850. //
  2851. // A new property has been added.
  2852. //
  2853. if ( nValuesAdd == nValuesAddTotal )
  2854. {
  2855. pTemp = (LPTSTR *) ReallocADsMem( aValuesAdd,
  2856. sizeof(LPTSTR) * nValuesAddTotal,
  2857. sizeof(LPTSTR) * nValuesAddTotal * 2 );
  2858. if ( pTemp == NULL )
  2859. {
  2860. hr = E_OUTOFMEMORY;
  2861. BAIL_ON_FAILURE(hr);
  2862. }
  2863. aValuesAdd = pTemp;
  2864. pTemp = NULL;
  2865. nValuesAddTotal *= 2;
  2866. }
  2867. nIndex = (((SCHEMAINFO *)_hSchema)->aPropertiesSearchTable[pOIDs[j]]).nIndex;
  2868. aValuesAdd[nValuesAdd++] =
  2869. (((SCHEMAINFO *)_hSchema)->aProperties[nIndex]).pszPropertyName;
  2870. j++;
  2871. }
  2872. else // ( pOIDs[j] == -1 || pOIDs[j] > pOIDsOld[k] )
  2873. {
  2874. // Some property has been removed, we need to read the current class
  2875. // set of "mayContain" or "mustContain" to make sure we
  2876. // aren't removing any "systemMustContain" or "systemMayContain"
  2877. // and we are not trying to remove any parent classes
  2878. // may/mustContain
  2879. if ( !fReadProperty )
  2880. {
  2881. LPTSTR *aValues = NULL;
  2882. int nCount = 0;
  2883. if ( _pszLDAPDn == NULL )
  2884. {
  2885. hr = BuildSchemaLDAPPathAndGetAttribute(
  2886. _Parent,
  2887. _Name,
  2888. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  2889. _pClassInfo == NULL,
  2890. _Credentials,
  2891. aStrings,
  2892. &_pszLDAPServer,
  2893. &_pszLDAPDn,
  2894. &_ld,
  2895. &res
  2896. );
  2897. BAIL_ON_FAILURE(hr);
  2898. hr = LdapFirstEntry(
  2899. _ld,
  2900. res,
  2901. &e
  2902. );
  2903. BAIL_ON_FAILURE(hr);
  2904. hr = LdapGetValues(
  2905. _ld,
  2906. e,
  2907. pszPropName,
  2908. &aValues,
  2909. &nCount
  2910. );
  2911. }
  2912. else
  2913. {
  2914. hr = LdapReadAttribute(
  2915. _pszLDAPServer,
  2916. _pszLDAPDn,
  2917. pszPropName,
  2918. &aValues,
  2919. &nCount,
  2920. _Credentials,
  2921. _dwPort
  2922. );
  2923. }
  2924. if ( hr == HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) )
  2925. {
  2926. hr = S_OK;
  2927. }
  2928. BAIL_ON_FAILURE(hr);
  2929. fReadProperty = TRUE;
  2930. if ( nCount > 0 )
  2931. {
  2932. hr = MakePropArrayFromStringArray( aValues,
  2933. nCount,
  2934. (SCHEMAINFO *) _hSchema,
  2935. &pOIDsCurrent,
  2936. &nNumOfOidsCurrent );
  2937. LdapValueFree( aValues );
  2938. BAIL_ON_FAILURE(hr);
  2939. }
  2940. }
  2941. //
  2942. // See if we can find the property that we want to remove from.
  2943. // We don't need to reset i since both arrays are sorted.
  2944. //
  2945. for ( fFound = FALSE; i < nNumOfOidsCurrent; i++ )
  2946. {
  2947. if ( pOIDsOld[k] == pOIDsCurrent[i] )
  2948. {
  2949. fFound = TRUE;
  2950. break;
  2951. }
  2952. else if ( pOIDsOld[k] < pOIDsCurrent[i] )
  2953. {
  2954. // Both arrays are sorted, so we can break here
  2955. break;
  2956. }
  2957. }
  2958. if ( nNumOfOidsCurrent == 0 || !fFound )
  2959. {
  2960. int err = NO_ERROR;
  2961. // This property is not in "mustContain" or "mayContain",
  2962. // so nothing can be removed
  2963. hr = E_ADS_SCHEMA_VIOLATION;
  2964. BAIL_ON_FAILURE(hr);
  2965. }
  2966. //
  2967. // Modify the request to remove the property here
  2968. //
  2969. if ( nValuesRemove == nValuesRemoveTotal )
  2970. {
  2971. pTemp = (LPTSTR *) ReallocADsMem( aValuesRemove,
  2972. sizeof(LPTSTR) * nValuesRemoveTotal,
  2973. sizeof(LPTSTR) * nValuesRemoveTotal * 2 );
  2974. if ( pTemp == NULL )
  2975. {
  2976. hr = E_OUTOFMEMORY;
  2977. BAIL_ON_FAILURE(hr);
  2978. }
  2979. aValuesRemove = pTemp;
  2980. pTemp = NULL;
  2981. nValuesRemoveTotal *= 2;
  2982. }
  2983. nIndex = (((SCHEMAINFO *)_hSchema)->aPropertiesSearchTable[pOIDsOld[k]]).nIndex;
  2984. aValuesRemove[nValuesRemove++] =
  2985. (((SCHEMAINFO *)_hSchema)->aProperties[nIndex]).pszPropertyName;
  2986. k++;
  2987. }
  2988. }
  2989. if ( nValuesAdd == 0 )
  2990. {
  2991. FreeADsMem( aValuesAdd );
  2992. aValuesAdd = NULL;
  2993. }
  2994. if ( nValuesRemove == 0 )
  2995. {
  2996. FreeADsMem( aValuesRemove );
  2997. aValuesRemove = NULL;
  2998. }
  2999. if ( aValuesAdd || aValuesRemove )
  3000. {
  3001. hr = AddModifyRequest(
  3002. aMods,
  3003. pdwNumOfMods,
  3004. pszPropName,
  3005. aValuesAdd,
  3006. aValuesRemove );
  3007. }
  3008. error:
  3009. if ( pOIDsCurrent )
  3010. FreeADsMem( pOIDsCurrent );
  3011. if (res)
  3012. LdapMsgFree(res);
  3013. if ( FAILED(hr))
  3014. {
  3015. if ( aValuesAdd )
  3016. FreeADsMem( aValuesAdd );
  3017. if ( aValuesRemove )
  3018. FreeADsMem( aValuesRemove );
  3019. }
  3020. RRETURN_EXP_IF_ERR(hr);
  3021. }
  3022. HRESULT CLDAPClass::AddModifyRequest(
  3023. LDAPModW ***aMods,
  3024. DWORD *pdwNumOfMods,
  3025. LPTSTR pszPropName,
  3026. LPTSTR *aValuesAdd,
  3027. LPTSTR *aValuesRemove
  3028. )
  3029. {
  3030. HRESULT hr = S_OK;
  3031. LDAPModW *aModsBuffer = NULL;
  3032. DWORD j = 0;
  3033. DWORD nCount = 0;
  3034. if ( aValuesAdd != NULL )
  3035. nCount++;
  3036. if ( aValuesRemove != NULL )
  3037. nCount++;
  3038. if ( nCount == 0 )
  3039. RRETURN(S_OK);
  3040. if ( *aMods == NULL )
  3041. {
  3042. *aMods = (LDAPModW **) AllocADsMem( (nCount + 1) * sizeof(LDAPModW *));
  3043. if ( *aMods == NULL )
  3044. {
  3045. hr = E_OUTOFMEMORY;
  3046. BAIL_ON_FAILURE(hr);
  3047. }
  3048. aModsBuffer = (LDAPModW *) AllocADsMem( nCount * sizeof(LDAPModW));
  3049. if ( aModsBuffer == NULL )
  3050. {
  3051. FreeADsMem( *aMods );
  3052. *aMods = NULL;
  3053. hr = E_OUTOFMEMORY;
  3054. BAIL_ON_FAILURE(hr);
  3055. }
  3056. }
  3057. else
  3058. {
  3059. LDAPModW **aModsTemp = NULL;
  3060. aModsTemp = (LDAPModW **) AllocADsMem(
  3061. (*pdwNumOfMods + nCount + 1) * sizeof(LDAPModW *));
  3062. if ( aModsTemp == NULL )
  3063. {
  3064. hr = E_OUTOFMEMORY;
  3065. BAIL_ON_FAILURE(hr);
  3066. }
  3067. aModsBuffer = (LDAPModW *) AllocADsMem(
  3068. (*pdwNumOfMods + nCount) * sizeof(LDAPModW));
  3069. if ( aModsBuffer == NULL )
  3070. {
  3071. FreeADsMem( aModsTemp );
  3072. hr = E_OUTOFMEMORY;
  3073. BAIL_ON_FAILURE(hr);
  3074. }
  3075. memcpy( aModsBuffer, **aMods, *pdwNumOfMods * sizeof(LDAPModW));
  3076. FreeADsMem( **aMods );
  3077. FreeADsMem( *aMods );
  3078. *aMods = aModsTemp;
  3079. for ( j = 0; j < *pdwNumOfMods; j++ )
  3080. {
  3081. (*aMods)[j] = &aModsBuffer[j];
  3082. }
  3083. }
  3084. if ( aValuesAdd )
  3085. {
  3086. (*aMods)[j] = &aModsBuffer[j];
  3087. aModsBuffer[j].mod_type = pszPropName;
  3088. aModsBuffer[j].mod_values = aValuesAdd;
  3089. aModsBuffer[j].mod_op |= LDAP_MOD_ADD;
  3090. j++;
  3091. }
  3092. if ( aValuesRemove )
  3093. {
  3094. (*aMods)[j] = &aModsBuffer[j];
  3095. aModsBuffer[j].mod_type = pszPropName;
  3096. aModsBuffer[j].mod_values = aValuesRemove;
  3097. aModsBuffer[j].mod_op |= LDAP_MOD_DELETE;
  3098. }
  3099. *pdwNumOfMods += nCount;
  3100. error:
  3101. RRETURN_EXP_IF_ERR(hr);
  3102. }
  3103. HRESULT
  3104. CLDAPClass::get_NTDSProp_Helper( THIS_ BSTR bstrName, VARIANT FAR *pvProp )
  3105. {
  3106. HRESULT hr = S_OK;
  3107. LPTSTR *aValues = NULL;
  3108. int nCount = 0;
  3109. LDAPMessage *res = NULL;
  3110. LDAPMessage *e = NULL;
  3111. LPTSTR aStrings[3];
  3112. aStrings[0] = TEXT("cn");
  3113. aStrings[1] = bstrName;
  3114. aStrings[2] = NULL;
  3115. if ( _pClassInfo == NULL ) // new class
  3116. {
  3117. hr = MakeVariantFromStringArray( NULL,
  3118. pvProp );
  3119. RRETURN_EXP_IF_ERR(hr);
  3120. }
  3121. //
  3122. // If the dn is NULL we have not got the info so fetch it.
  3123. //
  3124. if (_pszLDAPDn == NULL )
  3125. {
  3126. hr = BuildSchemaLDAPPathAndGetAttribute(
  3127. _Parent,
  3128. _Name,
  3129. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  3130. _pClassInfo == NULL,
  3131. _Credentials,
  3132. aStrings,
  3133. &_pszLDAPServer,
  3134. &_pszLDAPDn,
  3135. &_ld,
  3136. &res
  3137. );
  3138. BAIL_IF_ERROR(hr);
  3139. hr = LdapFirstEntry(
  3140. _ld,
  3141. res,
  3142. &e
  3143. );
  3144. BAIL_IF_ERROR(hr);
  3145. hr = LdapGetValues(
  3146. _ld,
  3147. e,
  3148. bstrName,
  3149. &aValues,
  3150. &nCount
  3151. );
  3152. }
  3153. else
  3154. {
  3155. hr = LdapReadAttribute(
  3156. _pszLDAPServer,
  3157. _pszLDAPDn,
  3158. bstrName,
  3159. &aValues,
  3160. &nCount,
  3161. _Credentials,
  3162. _dwPort
  3163. );
  3164. }
  3165. if ( hr == HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) )
  3166. {
  3167. hr = NO_ERROR;
  3168. }
  3169. BAIL_IF_ERROR(hr);
  3170. hr = MakeVariantFromStringArray( aValues,
  3171. pvProp );
  3172. BAIL_IF_ERROR(hr);
  3173. hr = put_VARIANT_Property( this, bstrName, *pvProp );
  3174. BAIL_IF_ERROR(hr);
  3175. hr = _pPropertyCache->ClearPropertyFlag( bstrName );
  3176. BAIL_IF_ERROR(hr);
  3177. cleanup:
  3178. if ( aValues )
  3179. LdapValueFree( aValues );
  3180. if (res)
  3181. LdapMsgFree(res);
  3182. RRETURN_EXP_IF_ERR(hr);
  3183. }
  3184. //
  3185. // Needed for dynamic dispid's in the property cache.
  3186. //
  3187. HRESULT
  3188. CLDAPClass::GetAttributeSyntax(
  3189. LPWSTR szPropertyName,
  3190. PDWORD pdwSyntaxId
  3191. )
  3192. {
  3193. HRESULT hr;
  3194. hr = LdapGetSyntaxOfAttributeOnServer(
  3195. _pszLDAPServer,
  3196. szPropertyName,
  3197. pdwSyntaxId,
  3198. _Credentials,
  3199. _dwPort
  3200. );
  3201. RRETURN_EXP_IF_ERR(hr);
  3202. }
  3203. /* IUmiHelperPrivate support. */
  3204. //+---------------------------------------------------------------------------
  3205. // Function: CLDAPClass::GetPropertiesHelper
  3206. //
  3207. // Synopsis: Returns an array of PPROPERTYINFO that points to the
  3208. // property definitions this class can hold.
  3209. //
  3210. // Arguments: ppProperties - Ret values for the property info.
  3211. // pdwCount - Ret value for the number of properties.
  3212. //
  3213. //
  3214. // Returns: HRESULT - S_OK or any failure error code.
  3215. //
  3216. // Modifies: ppProperties and pdwCount appropriately.
  3217. //
  3218. //----------------------------------------------------------------------------
  3219. STDMETHODIMP
  3220. CLDAPClass::GetPropertiesHelper(
  3221. void **ppProperties,
  3222. PDWORD pdwPropCount
  3223. )
  3224. {
  3225. HRESULT hr = S_OK;
  3226. PPROPERTYINFO *pPropArray = NULL;
  3227. DWORD dwPropCount = 0;
  3228. DWORD dwCtr;
  3229. SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) _hSchema;
  3230. //
  3231. // Initialize out params to default values.
  3232. //
  3233. *pdwPropCount = 0;
  3234. *ppProperties = NULL;
  3235. //
  3236. // If there is no classInfo then we do not have any further processing
  3237. // to do as there are no properties on this class.
  3238. //
  3239. if (!this->_pClassInfo) {
  3240. RRETURN(E_FAIL);
  3241. }
  3242. //
  3243. // We need to know how many entries are there in the list of properties.
  3244. // The total is made up of both the mandatory and optional properties.
  3245. // Note that we will adjust this value suitably as we process the array.
  3246. //
  3247. dwPropCount = _pClassInfo->nNumOfMayContain
  3248. + _pClassInfo->nNumOfMustContain;
  3249. pPropArray = (PPROPERTYINFO *) AllocADsMem(
  3250. sizeof(PPROPERTY*) * dwPropCount
  3251. );
  3252. if (!pPropArray) {
  3253. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3254. }
  3255. //
  3256. // Go through and get the info for the must contain.
  3257. //
  3258. for (
  3259. dwCtr = 0;
  3260. ((dwCtr < (_pClassInfo->nNumOfMustContain))
  3261. && (_pClassInfo->pOIDsMustContain[dwCtr] != -1));
  3262. dwCtr++)
  3263. {
  3264. //
  3265. // Assign the appropriate prop info ptrs from the may contain list.
  3266. //
  3267. pPropArray[dwCtr] = &(pSchemaInfo->aProperties[
  3268. (pSchemaInfo->aPropertiesSearchTable[
  3269. _pClassInfo->pOIDsMustContain[dwCtr]].nIndex
  3270. )]);
  3271. }
  3272. DWORD dwAdjust;
  3273. //
  3274. // We could have less than the number in the array if we hit -1, or
  3275. // -1 could be pointing correctly to the last element !!!
  3276. //
  3277. if ((_pClassInfo->pOIDsMustContain[dwCtr] == -1)
  3278. && (dwCtr < _pClassInfo->nNumOfMustContain)) {
  3279. dwCtr++;
  3280. }
  3281. dwAdjust = dwCtr;
  3282. //
  3283. // Now get the may contain information.
  3284. //
  3285. for (
  3286. dwCtr = 0;
  3287. ((dwCtr < (_pClassInfo->nNumOfMayContain))
  3288. && (_pClassInfo->pOIDsMayContain[dwCtr]) != -1);
  3289. dwCtr++)
  3290. {
  3291. DWORD dwTemp = dwCtr + dwAdjust;
  3292. pPropArray[dwTemp] = &(pSchemaInfo->aProperties[
  3293. (pSchemaInfo->aPropertiesSearchTable[
  3294. _pClassInfo->pOIDsMayContain[dwCtr]].nIndex
  3295. )]);
  3296. }
  3297. *ppProperties = (void *) pPropArray;
  3298. if ((_pClassInfo->pOIDsMayContain[dwCtr] == -1)
  3299. && (dwCtr < _pClassInfo->nNumOfMustContain)) {
  3300. *pdwPropCount = dwAdjust + dwCtr + 1;
  3301. }
  3302. else {
  3303. *pdwPropCount = dwAdjust + dwCtr;
  3304. }
  3305. error:
  3306. if (FAILED(hr)) {
  3307. if (pPropArray) {
  3308. FreeADsMem(pPropArray);
  3309. }
  3310. }
  3311. RRETURN(hr);
  3312. }
  3313. HRESULT
  3314. IsPropertyInList(
  3315. LPCWSTR pszName,
  3316. VARIANT vProp,
  3317. BOOL *pfInList
  3318. )
  3319. {
  3320. HRESULT hr = S_OK;
  3321. VARIANT *pvProp = &vProp;
  3322. SAFEARRAY *pArray = V_ARRAY(pvProp);
  3323. DWORD dwSLBound;
  3324. DWORD dwSUBound;
  3325. DWORD dwLength = 0;
  3326. VARIANT vVar;
  3327. VariantInit(&vVar);
  3328. *pfInList = FALSE;
  3329. hr = SafeArrayGetLBound(pArray,
  3330. 1,
  3331. (long FAR *)&dwSLBound
  3332. );
  3333. BAIL_ON_FAILURE(hr);
  3334. hr = SafeArrayGetUBound(pArray,
  3335. 1,
  3336. (long FAR *)&dwSUBound
  3337. );
  3338. BAIL_ON_FAILURE(hr);
  3339. dwLength = dwSUBound - dwSLBound;
  3340. //
  3341. // If there are 0 elements in cannot be in the list.
  3342. //
  3343. if (!dwLength) {
  3344. RRETURN(S_OK);
  3345. }
  3346. for (DWORD dwCtr = 0;
  3347. (dwCtr <= dwLength) && (*pfInList != TRUE);
  3348. dwCtr++)
  3349. {
  3350. //
  3351. // Go through the array to see if we find the name in the list.
  3352. //
  3353. VariantClear(&vVar);
  3354. hr = SafeArrayGetElement(pArray,
  3355. (long FAR *)&dwCtr,
  3356. &vVar
  3357. );
  3358. BAIL_ON_FAILURE(hr);
  3359. if (V_VT(&vVar) != VT_BSTR) {
  3360. BAIL_ON_FAILURE(hr = E_FAIL);
  3361. }
  3362. if (!_wcsicmp(pszName, vVar.bstrVal)) {
  3363. *pfInList = TRUE;
  3364. }
  3365. }
  3366. error:
  3367. VariantClear(&vVar);
  3368. RRETURN(hr);
  3369. }
  3370. //+---------------------------------------------------------------------------
  3371. // Function: CLDAPClass::GetOriginHelper
  3372. //
  3373. // Synopsis: Returns the name of the class this property originated on.
  3374. //
  3375. // Arguments: pszName - Name of the property whose origin is needed.
  3376. // pbstrOrigin - Return value - name of class.
  3377. //
  3378. // Returns: HRESULT - S_OK or any failure error code.
  3379. //
  3380. // Modifies: pbstrOrigin on success.
  3381. //
  3382. //----------------------------------------------------------------------------
  3383. STDMETHODIMP
  3384. CLDAPClass::GetOriginHelper(
  3385. LPCWSTR pszName,
  3386. BSTR *pbstrOrigin
  3387. )
  3388. {
  3389. HRESULT hr = S_OK;
  3390. CCredentials cCreds = _Credentials;
  3391. IUnknown *pUnk = NULL;
  3392. IADsContainer *pContainer = NULL;
  3393. BSTR bstrTemp = NULL;
  3394. DWORD dwAuthFlags = cCreds.GetAuthFlags();
  3395. BOOL fDone = FALSE;
  3396. BOOL fInMustContain = FALSE;
  3397. BOOL fInList = FALSE;
  3398. IADsClass *pClass = NULL;
  3399. IDispatch *pDispObj = NULL;
  3400. BOOL fMustContain = FALSE;
  3401. VARIANT vVar, vVarProps;
  3402. VariantInit(&vVar);
  3403. VariantInit(&vVarProps);
  3404. //
  3405. // If we are already at the top.
  3406. //
  3407. if (!_wcsicmp(_Name, L"top")) {
  3408. hr = ADsAllocString(L"top", pbstrOrigin);
  3409. RRETURN(hr);
  3410. }
  3411. //
  3412. // We want to chase up either the mandatory or optional list and
  3413. // not both. So we first update this flag.
  3414. //
  3415. hr = get_MandatoryProperties(&vVarProps);
  3416. BAIL_ON_FAILURE(hr);
  3417. hr = IsPropertyInList(pszName, vVarProps, &fInMustContain);
  3418. BAIL_ON_FAILURE(hr)
  3419. //
  3420. // Mask out the reserved flags - we want to be in ADSI land now.
  3421. //
  3422. cCreds.SetAuthFlags(dwAuthFlags & ~(ADS_AUTH_RESERVED));
  3423. //
  3424. // This will be the default class name to return.
  3425. //
  3426. hr = ADsAllocString(_Name, &bstrTemp);
  3427. BAIL_ON_FAILURE(hr);
  3428. //
  3429. // Need to get hold of the schema container.
  3430. //
  3431. hr = GetObject(_Parent, cCreds, (void **)&pUnk);
  3432. BAIL_ON_FAILURE(hr);
  3433. hr = pUnk->QueryInterface(IID_IADsContainer, (void **) &pContainer);
  3434. BAIL_ON_FAILURE(hr);
  3435. while (!fDone) {
  3436. //
  3437. // Need to keep finding the derived from until we hit top
  3438. // or we hit a class that does not support the attribute.
  3439. //
  3440. VariantClear(&vVar);
  3441. VariantClear(&vVarProps);
  3442. if (pDispObj) {
  3443. pDispObj->Release();
  3444. pDispObj = NULL;
  3445. }
  3446. if (!pClass) {
  3447. //
  3448. // Need to get the derived from for the current class.
  3449. //
  3450. hr = get_DerivedFrom(&vVar);
  3451. }
  3452. else {
  3453. hr = pClass->get_DerivedFrom(&vVar);
  3454. pClass->Release();
  3455. pClass = NULL;
  3456. }
  3457. //
  3458. // Get the derived from classes object.
  3459. //
  3460. hr = pContainer->GetObject(
  3461. L"Class",
  3462. vVar.bstrVal,
  3463. &pDispObj
  3464. );
  3465. BAIL_ON_FAILURE(hr);
  3466. hr = pDispObj->QueryInterface(
  3467. IID_IADsClass,
  3468. (void **) &pClass
  3469. );
  3470. BAIL_ON_FAILURE(hr);
  3471. if (!_wcsicmp(vVar.bstrVal, L"top")) {
  3472. fDone = TRUE;
  3473. }
  3474. if (fInMustContain) {
  3475. hr = pClass->get_MandatoryProperties(&vVarProps);
  3476. }
  3477. else {
  3478. hr = pClass->get_OptionalProperties(&vVarProps);
  3479. }
  3480. BAIL_ON_FAILURE(hr);
  3481. hr = IsPropertyInList(pszName, vVarProps, &fInList);
  3482. BAIL_ON_FAILURE(hr);
  3483. if (!fInList) {
  3484. //
  3485. // The value in temp is the correct class name
  3486. //
  3487. hr = ADsAllocString(bstrTemp, pbstrOrigin);
  3488. BAIL_ON_FAILURE(hr);
  3489. fDone = TRUE;
  3490. }
  3491. //
  3492. // This will be true only if we found the item in top.
  3493. //
  3494. if (fInList && fDone) {
  3495. hr = ADsAllocString(L"Top", pbstrOrigin);
  3496. BAIL_ON_FAILURE(hr);
  3497. }
  3498. if (bstrTemp) {
  3499. SysFreeString(bstrTemp);
  3500. bstrTemp = NULL;
  3501. }
  3502. //
  3503. // Need to get the current class name in bstrTemp.
  3504. //
  3505. hr = ADsAllocString(vVar.bstrVal, &bstrTemp);
  3506. BAIL_ON_FAILURE(hr);
  3507. }
  3508. //
  3509. // We will default to the current class.
  3510. //
  3511. if (!pbstrOrigin) {
  3512. hr = ADsAllocString(_Name, pbstrOrigin);
  3513. BAIL_ON_FAILURE(hr);
  3514. }
  3515. error:
  3516. if (bstrTemp) {
  3517. SysFreeString(bstrTemp);
  3518. }
  3519. VariantClear(&vVar);
  3520. VariantClear(&vVarProps);
  3521. if (pContainer) {
  3522. pContainer->Release();
  3523. }
  3524. if (pUnk) {
  3525. pUnk->Release();
  3526. }
  3527. if (pClass) {
  3528. pClass->Release();
  3529. }
  3530. if (pDispObj) {
  3531. pDispObj->Release();
  3532. }
  3533. RRETURN(hr);
  3534. }
  3535. /******************************************************************/
  3536. /* Class CLDAPProperty
  3537. /******************************************************************/
  3538. DEFINE_IDispatch_Implementation(CLDAPProperty)
  3539. DEFINE_IADs_Implementation(CLDAPProperty)
  3540. CLDAPProperty::CLDAPProperty()
  3541. : _pDispMgr( NULL ),
  3542. _pPropertyCache( NULL ),
  3543. _bstrSyntax( NULL ),
  3544. _hSchema( NULL ),
  3545. _pPropertyInfo( NULL ),
  3546. _pszLDAPServer(NULL),
  3547. _pszLDAPDn(NULL),
  3548. _fNTDS( TRUE ),
  3549. _ld( NULL )
  3550. {
  3551. ENLIST_TRACKING(CLDAPProperty);
  3552. }
  3553. CLDAPProperty::~CLDAPProperty()
  3554. {
  3555. delete _pDispMgr;
  3556. delete _pPropertyCache;
  3557. if ( _bstrSyntax ) {
  3558. ADsFreeString( _bstrSyntax );
  3559. }
  3560. if ( _hSchema ) {
  3561. SchemaClose( &_hSchema );
  3562. _hSchema = NULL;
  3563. }
  3564. if (_pszLDAPServer) {
  3565. FreeADsStr(_pszLDAPServer);
  3566. }
  3567. if (_pszLDAPDn) {
  3568. FreeADsStr(_pszLDAPDn);
  3569. }
  3570. if ( _ld ) {
  3571. LdapCloseObject( _ld );
  3572. _ld = NULL;
  3573. }
  3574. }
  3575. HRESULT
  3576. CLDAPProperty::CreateProperty(
  3577. BSTR bstrParent,
  3578. LDAP_SCHEMA_HANDLE hSchema,
  3579. BSTR bstrName,
  3580. PROPERTYINFO *pPropertyInfo,
  3581. CCredentials& Credentials,
  3582. DWORD dwObjectState,
  3583. REFIID riid,
  3584. void **ppvObj
  3585. )
  3586. {
  3587. CLDAPProperty FAR * pProperty = NULL;
  3588. HRESULT hr = S_OK;
  3589. BSTR bstrSyntax = NULL;
  3590. OBJECTINFO ObjectInfo;
  3591. POBJECTINFO pObjectInfo = &ObjectInfo;
  3592. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  3593. hr = AllocatePropertyObject(Credentials, &pProperty );
  3594. BAIL_ON_FAILURE(hr);
  3595. pProperty->_pPropertyInfo = pPropertyInfo;
  3596. SchemaAddRef( hSchema );
  3597. pProperty->_hSchema = hSchema;
  3598. if ( pPropertyInfo )
  3599. {
  3600. hr = put_BSTR_Property( pProperty, TEXT("attributeID"),
  3601. pPropertyInfo->pszOID);
  3602. if ( SUCCEEDED(hr))
  3603. {
  3604. hr = put_VARIANT_BOOL_Property( pProperty, TEXT("isSingleValued"),
  3605. (VARIANT_BOOL)pPropertyInfo->fSingleValued );
  3606. BAIL_ON_FAILURE(hr);
  3607. pProperty->_pPropertyCache->ClearAllPropertyFlags();
  3608. pProperty->_fNTDS = TRUE;
  3609. }
  3610. else
  3611. {
  3612. pProperty->_fNTDS = FALSE;
  3613. }
  3614. }
  3615. hr = ADsObject(bstrParent, pObjectInfo);
  3616. BAIL_ON_FAILURE(hr);
  3617. pProperty->_dwPort = pObjectInfo->PortNumber;
  3618. FreeObjectInfo(pObjectInfo);
  3619. pObjectInfo = NULL;
  3620. hr = pProperty->InitializeCoreObject(
  3621. bstrParent,
  3622. bstrName,
  3623. PROPERTY_CLASS_NAME,
  3624. CLSID_LDAPProperty,
  3625. dwObjectState );
  3626. BAIL_ON_FAILURE(hr);
  3627. //
  3628. // At this point update the info in the property cache
  3629. //
  3630. pProperty->_pPropertyCache->SetObjInformation(
  3631. &(pProperty->_Credentials),
  3632. pProperty->_pszLDAPServer,
  3633. pProperty->_dwPort
  3634. );
  3635. BAIL_ON_FAILURE(hr);
  3636. //
  3637. // Need to create the umi object if applicable.
  3638. //
  3639. if (Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
  3640. hr = ((CCoreADsObject*)pProperty)->InitUmiObject(
  3641. IntfPropsSchema,
  3642. pProperty->_pPropertyCache,
  3643. (IADs *) pProperty,
  3644. (IADs *) pProperty,
  3645. riid,
  3646. ppvObj,
  3647. &(pProperty->_Credentials),
  3648. pProperty->_dwPort,
  3649. pProperty->_pszLDAPServer,
  3650. pProperty->_pszLDAPDn
  3651. );
  3652. BAIL_ON_FAILURE(hr);
  3653. //
  3654. // Need to put syntax in the cache.
  3655. //
  3656. if (pProperty->_pPropertyInfo->pszSyntax) {
  3657. hr = GetFriendlyNameFromOID(
  3658. pProperty->_pPropertyInfo->pszSyntax,
  3659. &bstrSyntax
  3660. );
  3661. if (FAILED(hr)) {
  3662. //
  3663. // ok if this failed.
  3664. //
  3665. hr = S_OK;
  3666. }
  3667. else {
  3668. hr = put_BSTR_Property(
  3669. pProperty, TEXT("syntax"),
  3670. bstrSyntax
  3671. );
  3672. SysFreeString(bstrSyntax);
  3673. //
  3674. // Not critical failure
  3675. //
  3676. hr = S_OK;
  3677. }
  3678. }
  3679. //
  3680. // Name is a simulated propert used for UMI.
  3681. //
  3682. hr = put_BSTR_Property(
  3683. pProperty,
  3684. TEXT("Name"),
  3685. bstrName
  3686. );
  3687. BAIL_ON_FAILURE(hr);
  3688. RRETURN(S_OK);
  3689. }
  3690. //
  3691. // Get the LDAP path of the schema entry
  3692. //
  3693. hr = pProperty->QueryInterface( riid, ppvObj );
  3694. BAIL_ON_FAILURE(hr);
  3695. pProperty->Release();
  3696. RRETURN(hr);
  3697. error:
  3698. *ppvObj = NULL;
  3699. delete pProperty;
  3700. FreeObjectInfo(pObjectInfo);
  3701. RRETURN_EXP_IF_ERR(hr);
  3702. }
  3703. STDMETHODIMP
  3704. CLDAPProperty::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  3705. {
  3706. if (ppv == NULL) {
  3707. RRETURN(E_POINTER);
  3708. }
  3709. if (IsEqualIID(iid, IID_IUnknown))
  3710. {
  3711. *ppv = (IADsProperty FAR *) this;
  3712. }
  3713. else if (IsEqualIID(iid, IID_IDispatch))
  3714. {
  3715. *ppv = (IADs FAR *) this;
  3716. }
  3717. else if (IsEqualIID(iid, IID_ISupportErrorInfo))
  3718. {
  3719. *ppv = (ISupportErrorInfo FAR *) this;
  3720. }
  3721. else if (IsEqualIID(iid, IID_IADs))
  3722. {
  3723. *ppv = (IADs FAR *) this;
  3724. }
  3725. else if (IsEqualIID(iid, IID_IADsProperty))
  3726. {
  3727. *ppv = (IADsProperty FAR *) this;
  3728. }
  3729. else
  3730. {
  3731. *ppv = NULL;
  3732. return E_NOINTERFACE;
  3733. }
  3734. AddRef();
  3735. return NOERROR;
  3736. }
  3737. /* ISupportErrorInfo method */
  3738. STDMETHODIMP
  3739. CLDAPProperty::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
  3740. {
  3741. if (IsEqualIID(riid, IID_IADs) |
  3742. IsEqualIID(riid, IID_IADsProperty)) {
  3743. RRETURN(S_OK);
  3744. } else {
  3745. RRETURN(S_FALSE);
  3746. }
  3747. }
  3748. /* IADs methods */
  3749. STDMETHODIMP
  3750. CLDAPProperty::SetInfo(THIS)
  3751. {
  3752. HRESULT hr = S_OK;
  3753. BOOL fChanged = FALSE;
  3754. if ( !_fNTDS )
  3755. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  3756. if ( GetObjectState() == ADS_OBJECT_UNBOUND )
  3757. {
  3758. hr = LDAPCreateObject();
  3759. BAIL_ON_FAILURE(hr);
  3760. fChanged = TRUE;
  3761. //
  3762. // If the create succeded, set the object type to bound
  3763. //
  3764. SetObjectState(ADS_OBJECT_BOUND);
  3765. }
  3766. else
  3767. {
  3768. hr = LDAPSetObject( &fChanged );
  3769. BAIL_ON_FAILURE(hr);
  3770. }
  3771. //
  3772. // Need to refresh the schema
  3773. //
  3774. if ( SUCCEEDED(hr) && fChanged )
  3775. hr = LDAPRefreshSchema();
  3776. error:
  3777. RRETURN_EXP_IF_ERR(hr);
  3778. }
  3779. HRESULT
  3780. CLDAPProperty::LDAPSetObject( BOOL *pfChanged )
  3781. {
  3782. HRESULT hr = S_OK;
  3783. LDAPModW **aMod = NULL;
  3784. BOOL fNTSecDes = FALSE;
  3785. SECURITY_INFORMATION NewSeInfo;
  3786. *pfChanged = FALSE;
  3787. hr = _pPropertyCache->LDAPMarshallProperties(
  3788. &aMod,
  3789. &fNTSecDes,
  3790. &NewSeInfo
  3791. );
  3792. BAIL_ON_FAILURE(hr);
  3793. if ( aMod == NULL ) // There are no changes that needs to be modified
  3794. RRETURN(S_OK);
  3795. if ( _pszLDAPDn == NULL )
  3796. {
  3797. hr = BuildSchemaLDAPPath( _Parent,
  3798. _Name,
  3799. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  3800. &_pszLDAPServer,
  3801. &_pszLDAPDn,
  3802. _pPropertyInfo == NULL,
  3803. &_ld,
  3804. _Credentials
  3805. );
  3806. BAIL_ON_FAILURE(hr);
  3807. }
  3808. if ( _ld == NULL )
  3809. {
  3810. hr = LdapOpenObject(
  3811. _pszLDAPServer,
  3812. _pszLDAPDn,
  3813. &_ld,
  3814. _Credentials,
  3815. _dwPort
  3816. );
  3817. BAIL_ON_FAILURE(hr);
  3818. }
  3819. hr = LdapModifyS(
  3820. _ld,
  3821. _pszLDAPDn,
  3822. aMod
  3823. );
  3824. BAIL_ON_FAILURE(hr);
  3825. // We are successful at this point,
  3826. // So, clean up the flags in the cache so the same operation
  3827. // won't be repeated on the next SetInfo()
  3828. _pPropertyCache->ClearAllPropertyFlags();
  3829. *pfChanged = TRUE;
  3830. error:
  3831. if (aMod) {
  3832. if ( *aMod )
  3833. FreeADsMem( *aMod );
  3834. FreeADsMem( aMod );
  3835. }
  3836. RRETURN_EXP_IF_ERR(hr);
  3837. }
  3838. HRESULT
  3839. CLDAPProperty::LDAPCreateObject()
  3840. {
  3841. HRESULT hr = S_OK;
  3842. LDAPModW **aMod = NULL;
  3843. DWORD dwIndex = 0;
  3844. VARIANT v;
  3845. BOOL fNTSecDes= FALSE;
  3846. SECURITY_INFORMATION NewSeInfo;
  3847. //
  3848. // Get the LDAP path of the schema entry
  3849. //
  3850. if ( (_pszLDAPServer == NULL) && (_pszLDAPDn == NULL))
  3851. {
  3852. hr = BuildSchemaLDAPPath( _Parent,
  3853. _Name,
  3854. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  3855. &_pszLDAPServer,
  3856. &_pszLDAPDn,
  3857. _pPropertyInfo == NULL,
  3858. &_ld,
  3859. _Credentials
  3860. );
  3861. BAIL_ON_FAILURE(hr);
  3862. }
  3863. if ( _pPropertyCache->findproperty( TEXT("objectClass"), &dwIndex )
  3864. == E_ADS_PROPERTY_NOT_FOUND )
  3865. {
  3866. VariantInit(&v);
  3867. v.vt = VT_BSTR;
  3868. V_BSTR(&v) = NT_SCHEMA_PROPERTY_NAME;
  3869. hr = Put( TEXT("objectClass"), v );
  3870. BAIL_ON_FAILURE(hr);
  3871. }
  3872. if ( _pPropertyCache->findproperty( TEXT("cn"), &dwIndex )
  3873. == E_ADS_PROPERTY_NOT_FOUND )
  3874. {
  3875. VariantInit(&v);
  3876. v.vt = VT_BSTR;
  3877. V_BSTR(&v) = _Name;
  3878. hr = Put( TEXT("cn"), v );
  3879. BAIL_ON_FAILURE(hr);
  3880. }
  3881. if ( _pPropertyCache->findproperty( TEXT("lDAPDisplayName"), &dwIndex )
  3882. == E_ADS_PROPERTY_NOT_FOUND )
  3883. {
  3884. VariantInit(&v);
  3885. v.vt = VT_BSTR;
  3886. V_BSTR(&v) = _Name;
  3887. hr = Put( TEXT("lDAPDisplayName"), v );
  3888. BAIL_ON_FAILURE(hr);
  3889. }
  3890. hr = _pPropertyCache->LDAPMarshallProperties(
  3891. &aMod,
  3892. &fNTSecDes,
  3893. &NewSeInfo
  3894. );
  3895. BAIL_ON_FAILURE(hr);
  3896. if ( _ld == NULL )
  3897. {
  3898. hr = LdapOpenObject(
  3899. _pszLDAPServer,
  3900. _pszLDAPDn,
  3901. &_ld,
  3902. _Credentials,
  3903. _dwPort
  3904. );
  3905. BAIL_ON_FAILURE(hr);
  3906. }
  3907. hr = LdapAddS(
  3908. _ld,
  3909. _pszLDAPDn,
  3910. aMod
  3911. );
  3912. BAIL_ON_FAILURE(hr);
  3913. // We are successful at this point,
  3914. // So, clean up the flags in the cache so the same operation
  3915. // won't be repeated on the next SetInfo()
  3916. _pPropertyCache->ClearAllPropertyFlags();
  3917. error:
  3918. if (aMod) {
  3919. if ( *aMod )
  3920. FreeADsMem( *aMod );
  3921. FreeADsMem( aMod );
  3922. }
  3923. RRETURN_EXP_IF_ERR(hr);
  3924. }
  3925. HRESULT
  3926. CLDAPProperty::LDAPRefreshSchema(THIS)
  3927. {
  3928. HRESULT hr = S_OK;
  3929. if (( _pszLDAPServer == NULL) && (_pszLDAPDn == NULL))
  3930. {
  3931. hr = BuildSchemaLDAPPath( _Parent,
  3932. _Name,
  3933. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  3934. &_pszLDAPServer,
  3935. &_pszLDAPDn,
  3936. _pPropertyInfo == NULL,
  3937. &_ld,
  3938. _Credentials
  3939. );
  3940. BAIL_ON_FAILURE(hr);
  3941. }
  3942. //
  3943. // Make the old schema obsolete and get the new schema
  3944. // We cannot delete the old schema since other objects might have
  3945. // references to it.
  3946. //
  3947. hr = LdapMakeSchemaCacheObsolete(
  3948. _pszLDAPServer,
  3949. _Credentials,
  3950. _dwPort
  3951. );
  3952. BAIL_ON_FAILURE(hr);
  3953. error:
  3954. RRETURN_EXP_IF_ERR(hr);
  3955. }
  3956. STDMETHODIMP
  3957. CLDAPProperty::GetInfo(THIS)
  3958. {
  3959. HRESULT hr = S_OK;
  3960. BSTR bstrSyntax = NULL;
  3961. if ( GetObjectState() == ADS_OBJECT_UNBOUND )
  3962. RRETURN_EXP_IF_ERR(E_ADS_OBJECT_UNBOUND);
  3963. hr = LDAPRefreshSchema();
  3964. BAIL_ON_FAILURE(hr);
  3965. SchemaClose( &_hSchema );
  3966. hr = SchemaOpen( _pszLDAPServer, &_hSchema, _Credentials, _dwPort );
  3967. BAIL_ON_FAILURE(hr);
  3968. //
  3969. // Find the new property info in the new schemainfo
  3970. //
  3971. hr = SchemaGetPropertyInfo(
  3972. _hSchema,
  3973. _Name,
  3974. &_pPropertyInfo );
  3975. BAIL_ON_FAILURE( hr );
  3976. if ( _pPropertyInfo == NULL )
  3977. {
  3978. // Property name not found, set error
  3979. hr = E_ADS_BAD_PATHNAME;
  3980. BAIL_ON_FAILURE(hr);
  3981. }
  3982. _pPropertyCache->flushpropertycache();
  3983. hr = put_BSTR_Property( this, TEXT("attributeID"),
  3984. _pPropertyInfo->pszOID);
  3985. BAIL_ON_FAILURE(hr);
  3986. if ( _bstrSyntax )
  3987. {
  3988. ADsFreeString( _bstrSyntax );
  3989. _bstrSyntax = NULL;
  3990. }
  3991. hr = put_VARIANT_BOOL_Property( this, TEXT("isSingleValued"),
  3992. (VARIANT_BOOL)_pPropertyInfo->fSingleValued );
  3993. BAIL_ON_FAILURE(hr);
  3994. //
  3995. // If we are calling from Umi land then we need to set
  3996. // additional properties.
  3997. //
  3998. if (_Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
  3999. if (_pPropertyInfo->pszSyntax) {
  4000. hr = GetFriendlyNameFromOID(
  4001. _pPropertyInfo->pszSyntax,
  4002. &bstrSyntax
  4003. );
  4004. if (FAILED(hr)) {
  4005. //
  4006. // ok if this failed.
  4007. //
  4008. hr = S_OK;
  4009. }
  4010. else {
  4011. hr = put_BSTR_Property(
  4012. this, TEXT("syntax"),
  4013. bstrSyntax
  4014. );
  4015. SysFreeString(bstrSyntax);
  4016. //
  4017. // Not critical failure
  4018. //
  4019. hr = S_OK;
  4020. }
  4021. }
  4022. //
  4023. // Name is a simulated propert used for UMI.
  4024. //
  4025. hr = put_BSTR_Property(
  4026. this,
  4027. TEXT("Name"),
  4028. _Name
  4029. );
  4030. BAIL_ON_FAILURE(hr);
  4031. } // special props for Umi.
  4032. if (_fNTDS) {
  4033. hr = GetNTDSSchemaInfo(TRUE);
  4034. }
  4035. _pPropertyCache->ClearAllPropertyFlags();
  4036. _pPropertyCache->setGetInfoFlag();
  4037. error:
  4038. if (bstrSyntax) {
  4039. SysFreeString(bstrSyntax);
  4040. }
  4041. RRETURN_EXP_IF_ERR(hr);
  4042. }
  4043. //
  4044. // Helper function for Umi - defined in CCoreADsObject.
  4045. //
  4046. STDMETHODIMP
  4047. CLDAPProperty::GetInfo(DWORD dwFlags)
  4048. {
  4049. HRESULT hr = S_OK;
  4050. if (dwFlags == GETINFO_FLAG_EXPLICIT) {
  4051. RRETURN(GetInfo());
  4052. }
  4053. else if (_fNTDS
  4054. && dwFlags != GETINFO_FLAG_IMPLICIT_AS_NEEDED
  4055. ) {
  4056. //
  4057. // Read the extra NTDS specific schema properties.
  4058. //
  4059. hr = GetNTDSSchemaInfo(FALSE);
  4060. }
  4061. //
  4062. // Any other flags means nothing to do.
  4063. //
  4064. RRETURN(hr);
  4065. }
  4066. HRESULT
  4067. CLDAPProperty::GetNTDSSchemaInfo(
  4068. BOOL fForce
  4069. )
  4070. {
  4071. HRESULT hr = S_OK;
  4072. LPTSTR aStrings[] = {
  4073. TEXT("cn"),
  4074. TEXT("schemaIDGUID"),
  4075. TEXT("rangeUpper"),
  4076. TEXT("rangeLower"),
  4077. NULL
  4078. };
  4079. LDAPMessage *res = NULL;
  4080. if (_pszLDAPDn == NULL) {
  4081. //
  4082. // Need to get the dn for this object and also
  4083. // the attributes we are interested in.
  4084. //
  4085. hr = BuildSchemaLDAPPathAndGetAttribute(
  4086. _Parent,
  4087. _Name,
  4088. ((SCHEMAINFO*)_hSchema)->pszSubSchemaSubEntry,
  4089. _pPropertyInfo == NULL,
  4090. _Credentials,
  4091. aStrings,
  4092. &_pszLDAPServer,
  4093. &_pszLDAPDn,
  4094. &_ld,
  4095. &res
  4096. );
  4097. }
  4098. else {
  4099. //
  4100. // Looks like we just need the attributes in this case.
  4101. //
  4102. hr = LdapSearchS(
  4103. _ld,
  4104. _pszLDAPDn,
  4105. LDAP_SCOPE_BASE,
  4106. L"(objectClass=*)",
  4107. aStrings,
  4108. FALSE,
  4109. &res
  4110. );
  4111. }
  4112. BAIL_ON_FAILURE(hr);
  4113. //
  4114. // If we succeeded we should unmarshall properties into the cache.
  4115. //
  4116. hr = _pPropertyCache->LDAPUnMarshallProperties(
  4117. _pszLDAPServer,
  4118. _ld,
  4119. res,
  4120. fForce,
  4121. _Credentials
  4122. );
  4123. BAIL_ON_FAILURE(hr);
  4124. _pPropertyCache->setGetInfoFlag();
  4125. error:
  4126. if (res) {
  4127. LdapMsgFree(res);
  4128. }
  4129. RRETURN(hr);
  4130. }
  4131. STDMETHODIMP
  4132. CLDAPProperty::Get(THIS_ BSTR bstrName, VARIANT FAR* pvProp)
  4133. {
  4134. HRESULT hr = S_OK;
  4135. DWORD dwSyntaxId;
  4136. LDAPOBJECTARRAY ldapSrcObjects;
  4137. DWORD dwStatus = 0;
  4138. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  4139. //
  4140. // For folks who know now what they do.
  4141. //
  4142. if (!pvProp) {
  4143. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  4144. }
  4145. //
  4146. // retrieve data object from cache; if one exists
  4147. //
  4148. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  4149. hr = _pPropertyCache->unboundgetproperty(
  4150. bstrName,
  4151. &dwSyntaxId,
  4152. &dwStatus,
  4153. &ldapSrcObjects
  4154. );
  4155. // For backward compatibility
  4156. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  4157. hr = E_FAIL;
  4158. }
  4159. } else {
  4160. hr = _pPropertyCache->getproperty(
  4161. bstrName,
  4162. &dwSyntaxId,
  4163. &dwStatus,
  4164. &ldapSrcObjects
  4165. );
  4166. // For backward compatibility
  4167. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  4168. hr = E_ADS_PROPERTY_NOT_FOUND;
  4169. }
  4170. }
  4171. BAIL_ON_FAILURE(hr);
  4172. //
  4173. // translate the Ldap objects to variants
  4174. //
  4175. if ( ldapSrcObjects.dwCount == 1 ) {
  4176. hr = LdapTypeToVarTypeCopy(
  4177. _pszLDAPServer,
  4178. _Credentials,
  4179. ldapSrcObjects.pLdapObjects,
  4180. dwSyntaxId,
  4181. pvProp
  4182. );
  4183. } else {
  4184. hr = LdapTypeToVarTypeCopyConstruct(
  4185. _pszLDAPServer,
  4186. _Credentials,
  4187. ldapSrcObjects,
  4188. dwSyntaxId,
  4189. pvProp
  4190. );
  4191. }
  4192. BAIL_ON_FAILURE(hr);
  4193. error:
  4194. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  4195. RRETURN_EXP_IF_ERR(hr);
  4196. }
  4197. STDMETHODIMP
  4198. CLDAPProperty::Put(THIS_ BSTR bstrName, VARIANT vProp)
  4199. {
  4200. HRESULT hr = S_OK;
  4201. DWORD dwSyntaxId = 0;
  4202. DWORD dwIndex = 0;
  4203. LDAPOBJECTARRAY ldapDestObjects;
  4204. DWORD dwNumValues = 0;
  4205. VARIANT * pVarArray = NULL;
  4206. VARIANT * pvProp = NULL;
  4207. VARIANT vDefProp;
  4208. VariantInit(&vDefProp);
  4209. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  4210. hr = SchemaGetSyntaxOfAttribute( _hSchema, bstrName, &dwSyntaxId );
  4211. if (FAILED(hr)) {
  4212. //
  4213. // Need to see if this is syntax if so we special case
  4214. // for Umi Objects.
  4215. //
  4216. if (!_wcsicmp(L"syntax", bstrName)) {
  4217. dwSyntaxId = LDAPTYPE_CASEIGNORESTRING;
  4218. hr = S_OK;
  4219. }
  4220. }
  4221. BAIL_ON_FAILURE(hr);
  4222. if ( dwSyntaxId == LDAPTYPE_UNKNOWN )
  4223. {
  4224. hr = E_ADS_CANT_CONVERT_DATATYPE;
  4225. BAIL_ON_FAILURE(hr);
  4226. }
  4227. //
  4228. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  4229. // We should dereference a VT_BYREF|VT_VARIANT once and see
  4230. // what's inside.
  4231. //
  4232. pvProp = &vProp;
  4233. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  4234. pvProp = V_VARIANTREF(&vProp);
  4235. }
  4236. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  4237. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  4238. hr = ConvertSafeArrayToVariantArray(
  4239. *pvProp,
  4240. &pVarArray,
  4241. &dwNumValues
  4242. );
  4243. // returns E_FAIL if *pvProp is invalid
  4244. if (hr == E_FAIL)
  4245. hr = E_ADS_BAD_PARAMETER;
  4246. BAIL_ON_FAILURE(hr);
  4247. pvProp = pVarArray;
  4248. }else {
  4249. //
  4250. // If pvProp is a reference to a fundamental type,
  4251. // we have to dereference it once.
  4252. //
  4253. if (V_ISBYREF(pvProp)) {
  4254. hr = VariantCopyInd(&vDefProp, pvProp);
  4255. BAIL_ON_FAILURE(hr);
  4256. pvProp = &vDefProp;
  4257. }
  4258. dwNumValues = 1;
  4259. }
  4260. #if 0
  4261. //
  4262. // check if this is a legal property for this object,
  4263. //
  4264. hr = ValidatePropertyinCache(
  4265. szLDAPTreeName,
  4266. _ADsClass,
  4267. bstrName,
  4268. &dwSyntaxId
  4269. );
  4270. BAIL_ON_FAILURE(hr);
  4271. #endif
  4272. //
  4273. // check if the variant maps to the syntax of this property
  4274. //
  4275. if ( dwNumValues > 0 )
  4276. {
  4277. hr = VarTypeToLdapTypeCopyConstruct(
  4278. _pszLDAPServer,
  4279. _Credentials,
  4280. dwSyntaxId,
  4281. pvProp,
  4282. dwNumValues,
  4283. &ldapDestObjects
  4284. );
  4285. BAIL_ON_FAILURE(hr);
  4286. }
  4287. //
  4288. // Find this property in the cache
  4289. //
  4290. hr = _pPropertyCache->findproperty(
  4291. bstrName,
  4292. &dwIndex
  4293. );
  4294. //
  4295. // If this property does not exist in the
  4296. // cache, add this property into the cache.
  4297. //
  4298. if (FAILED(hr)) {
  4299. hr = _pPropertyCache->addproperty( bstrName );
  4300. BAIL_ON_FAILURE(hr);
  4301. }
  4302. //
  4303. // Now update the property in the cache
  4304. //
  4305. hr = _pPropertyCache->putproperty(
  4306. bstrName,
  4307. PROPERTY_UPDATE,
  4308. dwSyntaxId,
  4309. ldapDestObjects
  4310. );
  4311. BAIL_ON_FAILURE(hr);
  4312. error:
  4313. VariantClear(&vDefProp);
  4314. LdapTypeFreeLdapObjects( &ldapDestObjects );
  4315. if (pVarArray) {
  4316. DWORD i = 0;
  4317. for (i = 0; i < dwNumValues; i++) {
  4318. VariantClear(pVarArray + i);
  4319. }
  4320. FreeADsMem(pVarArray);
  4321. }
  4322. RRETURN_EXP_IF_ERR(hr);
  4323. }
  4324. STDMETHODIMP
  4325. CLDAPProperty::GetEx(THIS_ BSTR bstrName, VARIANT FAR* pvProp)
  4326. {
  4327. HRESULT hr = S_OK;
  4328. DWORD dwSyntaxId;
  4329. DWORD dwNumValues;
  4330. DWORD dwStatus = 0;
  4331. LDAPOBJECTARRAY ldapSrcObjects;
  4332. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  4333. //
  4334. // For those who know no not what they do
  4335. //
  4336. if (!pvProp) {
  4337. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  4338. }
  4339. //
  4340. // retrieve data object from cache; if one exists
  4341. //
  4342. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  4343. hr = _pPropertyCache->unboundgetproperty(
  4344. bstrName,
  4345. &dwSyntaxId,
  4346. &dwStatus,
  4347. &ldapSrcObjects
  4348. );
  4349. // For backward compatibility
  4350. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  4351. hr = E_FAIL;
  4352. }
  4353. } else {
  4354. hr = _pPropertyCache->getproperty(
  4355. bstrName,
  4356. &dwSyntaxId,
  4357. &dwStatus,
  4358. &ldapSrcObjects
  4359. );
  4360. // For backward compatibility
  4361. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  4362. hr = E_ADS_PROPERTY_NOT_FOUND;
  4363. }
  4364. }
  4365. BAIL_ON_FAILURE(hr);
  4366. //
  4367. // translate the Ldap objects to variants
  4368. //
  4369. hr = LdapTypeToVarTypeCopyConstruct(
  4370. _pszLDAPServer,
  4371. _Credentials,
  4372. ldapSrcObjects,
  4373. dwSyntaxId,
  4374. pvProp
  4375. );
  4376. BAIL_ON_FAILURE(hr);
  4377. error:
  4378. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  4379. RRETURN_EXP_IF_ERR(hr);
  4380. }
  4381. STDMETHODIMP
  4382. CLDAPProperty::PutEx(THIS_ long lnControlCode, BSTR bstrName, VARIANT vProp)
  4383. {
  4384. HRESULT hr = S_OK;
  4385. DWORD dwSyntaxId = 0;
  4386. DWORD dwFlags = 0;
  4387. DWORD dwIndex = 0;
  4388. LDAPOBJECTARRAY ldapDestObjects;
  4389. DWORD dwNumValues = 0;
  4390. VARIANT * pVarArray = NULL;
  4391. VARIANT * pvProp = NULL;
  4392. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  4393. switch (lnControlCode) {
  4394. case ADS_PROPERTY_CLEAR:
  4395. dwFlags = PROPERTY_DELETE;
  4396. break;
  4397. case ADS_PROPERTY_UPDATE:
  4398. dwFlags = PROPERTY_UPDATE;
  4399. break;
  4400. default:
  4401. RRETURN_EXP_IF_ERR(hr = E_ADS_BAD_PARAMETER);
  4402. }
  4403. hr = SchemaGetSyntaxOfAttribute( _hSchema, bstrName, &dwSyntaxId );
  4404. BAIL_ON_FAILURE(hr);
  4405. if ( dwSyntaxId == LDAPTYPE_UNKNOWN )
  4406. {
  4407. hr = E_ADS_CANT_CONVERT_DATATYPE;
  4408. BAIL_ON_FAILURE(hr);
  4409. }
  4410. #if 0
  4411. //
  4412. // check if this is a legal property for this object,
  4413. //
  4414. hr = ValidatePropertyinCache(
  4415. szLDAPTreeName,
  4416. _ADsClass,
  4417. bstrName,
  4418. &dwSyntaxId
  4419. );
  4420. BAIL_ON_FAILURE(hr);
  4421. #endif
  4422. if ( dwFlags != PROPERTY_DELETE )
  4423. {
  4424. //
  4425. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  4426. // We should dereference a VT_BYREF|VT_VARIANT once and see
  4427. // what's inside.
  4428. //
  4429. pvProp = &vProp;
  4430. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  4431. pvProp = V_VARIANTREF(&vProp);
  4432. }
  4433. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  4434. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  4435. hr = ConvertSafeArrayToVariantArray(
  4436. *pvProp,
  4437. &pVarArray,
  4438. &dwNumValues
  4439. );
  4440. // returns E_FAIL if *pvProp is invalid
  4441. if (hr == E_FAIL)
  4442. hr = E_ADS_BAD_PARAMETER;
  4443. BAIL_ON_FAILURE(hr);
  4444. pvProp = pVarArray;
  4445. } else {
  4446. hr = E_FAIL;
  4447. BAIL_ON_FAILURE(hr);
  4448. }
  4449. //
  4450. // check if the variant maps to the syntax of this property
  4451. //
  4452. if ( dwNumValues > 0 )
  4453. {
  4454. hr = VarTypeToLdapTypeCopyConstruct(
  4455. _pszLDAPServer,
  4456. _Credentials,
  4457. dwSyntaxId,
  4458. pvProp,
  4459. dwNumValues,
  4460. &ldapDestObjects
  4461. );
  4462. BAIL_ON_FAILURE(hr);
  4463. }
  4464. }
  4465. //
  4466. // Find this property in the cache
  4467. //
  4468. hr = _pPropertyCache->findproperty(
  4469. bstrName,
  4470. &dwIndex
  4471. );
  4472. //
  4473. // If this property does not exist in the
  4474. // cache, add this property into the cache.
  4475. //
  4476. if (FAILED(hr)) {
  4477. hr = _pPropertyCache->addproperty( bstrName );
  4478. BAIL_ON_FAILURE(hr);
  4479. }
  4480. //
  4481. // Now update the property in the cache
  4482. //
  4483. hr = _pPropertyCache->putproperty(
  4484. bstrName,
  4485. PROPERTY_UPDATE,
  4486. dwSyntaxId,
  4487. ldapDestObjects
  4488. );
  4489. BAIL_ON_FAILURE(hr);
  4490. error:
  4491. LdapTypeFreeLdapObjects( &ldapDestObjects );
  4492. if (pVarArray) {
  4493. DWORD i = 0;
  4494. for (i = 0; i < dwNumValues; i++) {
  4495. VariantClear(pVarArray + i);
  4496. }
  4497. FreeADsMem(pVarArray);
  4498. }
  4499. RRETURN_EXP_IF_ERR(hr);
  4500. }
  4501. STDMETHODIMP
  4502. CLDAPProperty::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
  4503. {
  4504. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4505. }
  4506. /* IADsProperty methods */
  4507. STDMETHODIMP
  4508. CLDAPProperty::get_OID( THIS_ BSTR FAR *retval )
  4509. {
  4510. HRESULT hr;
  4511. if ( !retval )
  4512. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4513. if ( _fNTDS )
  4514. {
  4515. GET_PROPERTY_BSTR( this, attributeID );
  4516. }
  4517. else if ( _pPropertyInfo )
  4518. {
  4519. hr = ADsAllocString( _pPropertyInfo->pszOID?
  4520. _pPropertyInfo->pszOID : TEXT(""), retval);
  4521. }
  4522. else
  4523. {
  4524. hr = ADsAllocString( TEXT(""), retval );
  4525. }
  4526. RRETURN_EXP_IF_ERR(hr);
  4527. }
  4528. STDMETHODIMP
  4529. CLDAPProperty::put_OID( THIS_ BSTR bstrOID )
  4530. {
  4531. if ( !_fNTDS )
  4532. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4533. HRESULT hr = put_BSTR_Property( this, TEXT("attributeID"), bstrOID );
  4534. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4535. {
  4536. _fNTDS = FALSE;
  4537. hr = E_NOTIMPL;
  4538. }
  4539. RRETURN_EXP_IF_ERR(hr);
  4540. }
  4541. STDMETHODIMP
  4542. CLDAPProperty::get_Syntax( THIS_ BSTR FAR *retval )
  4543. {
  4544. HRESULT hr = S_OK;
  4545. if ( !retval )
  4546. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4547. if ( _fNTDS )
  4548. {
  4549. if ( _bstrSyntax ) // New property or syntax has been reset
  4550. {
  4551. hr = ADsAllocString( _bstrSyntax, retval);
  4552. } else if (_pPropertyInfo && !_pPropertyInfo->pszSyntax) {
  4553. //
  4554. // New property but syntax has not been set
  4555. //
  4556. hr = E_ADS_PROPERTY_NOT_FOUND;
  4557. }
  4558. }
  4559. //
  4560. // Need to return if hr or retVal as we have what we need
  4561. //
  4562. if (FAILED(hr) || _bstrSyntax) {
  4563. RRETURN_EXP_IF_ERR(hr);
  4564. }
  4565. // If we have the syntax in _pPropertyInfo we need to
  4566. // continue and see if we can get a friendly name to return.
  4567. if ( _pPropertyInfo ) {
  4568. if (_pPropertyInfo->pszSyntax) {
  4569. if (!GetFriendlyNameFromOID(
  4570. _pPropertyInfo->pszSyntax, retval)
  4571. ) {
  4572. // in this case we want to set the retVal
  4573. // to the OID as we could not find a match
  4574. hr = ADsAllocString(_pPropertyInfo->pszSyntax, retval);
  4575. }
  4576. }
  4577. } else {
  4578. hr = ADsAllocString( TEXT(""), retval );
  4579. }
  4580. RRETURN_EXP_IF_ERR(hr);
  4581. }
  4582. STDMETHODIMP
  4583. CLDAPProperty::put_Syntax( THIS_ BSTR bstrSyntax )
  4584. {
  4585. if ( !_fNTDS )
  4586. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4587. LPTSTR pszOID;
  4588. DWORD dwOMSyntax;
  4589. HRESULT hr = S_OK;
  4590. BYTE btDNWithBinary[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x14, 0x01,
  4591. 0x01, 0x01, 0x0B };
  4592. BYTE btDNWithString[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x14, 0x01,
  4593. 0x01, 0x01, 0x0C
  4594. };
  4595. if ( GetSyntaxOID( bstrSyntax, &pszOID, &dwOMSyntax))
  4596. {
  4597. hr = put_BSTR_Property( this, TEXT("attributeSyntax"),
  4598. pszOID );
  4599. BAIL_ON_FAILURE(hr);
  4600. hr = put_LONG_Property( this, TEXT("oMSyntax"),
  4601. dwOMSyntax );
  4602. BAIL_ON_FAILURE(hr);
  4603. if ( _bstrSyntax )
  4604. ADsFreeString( _bstrSyntax );
  4605. hr = ADsAllocString( bstrSyntax, &_bstrSyntax );
  4606. BAIL_ON_FAILURE(hr);
  4607. //
  4608. // We need to handle the special case of DNWithBinary
  4609. // and DNString
  4610. //
  4611. if (_wcsicmp(bstrSyntax, L"DNWithBinary") == 0) {
  4612. //
  4613. // Need to set additional byte attribute
  4614. //
  4615. hr = put_OCTETSTRING_Property(
  4616. this,
  4617. TEXT("omObjectClass"),
  4618. btDNWithBinary,
  4619. (sizeof(btDNWithBinary)/sizeof(btDNWithBinary[0]))
  4620. );
  4621. BAIL_ON_FAILURE(hr);
  4622. }
  4623. else if (_wcsicmp(bstrSyntax, L"DNWithString") == 0) {
  4624. //
  4625. // Need to set omObjectClass here too
  4626. //
  4627. hr = put_OCTETSTRING_Property(
  4628. this,
  4629. TEXT("omObjectClass"),
  4630. btDNWithString,
  4631. (sizeof(btDNWithString)/sizeof(btDNWithString[0]))
  4632. );
  4633. BAIL_ON_FAILURE(hr);
  4634. }
  4635. }
  4636. else
  4637. {
  4638. // Unknown syntax
  4639. hr = E_ADS_BAD_PARAMETER;
  4640. BAIL_ON_FAILURE(hr);
  4641. }
  4642. error:
  4643. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4644. {
  4645. _fNTDS = FALSE;
  4646. hr = E_NOTIMPL;
  4647. }
  4648. RRETURN_EXP_IF_ERR(hr);
  4649. }
  4650. STDMETHODIMP
  4651. CLDAPProperty::get_MaxRange( THIS_ long FAR *plMaxRange )
  4652. {
  4653. HRESULT hr = S_OK;
  4654. if ( !plMaxRange )
  4655. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4656. if ( !_fNTDS )
  4657. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4658. hr = get_LONG_Property(this, TEXT("rangeUpper"), plMaxRange );
  4659. if ( SUCCEEDED(hr) )
  4660. RRETURN(hr);
  4661. if ( _pPropertyInfo == NULL ) // new class
  4662. {
  4663. hr = E_ADS_PROPERTY_NOT_SET;
  4664. RRETURN_EXP_IF_ERR(hr);
  4665. }
  4666. RRETURN_EXP_IF_ERR(hr);
  4667. }
  4668. STDMETHODIMP
  4669. CLDAPProperty::put_MaxRange( THIS_ long lMaxRange )
  4670. {
  4671. if ( !_fNTDS )
  4672. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4673. HRESULT hr = put_LONG_Property( this, TEXT("rangeUpper"),
  4674. lMaxRange );
  4675. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4676. {
  4677. _fNTDS = FALSE;
  4678. hr = E_NOTIMPL;
  4679. }
  4680. RRETURN_EXP_IF_ERR(hr);
  4681. }
  4682. STDMETHODIMP
  4683. CLDAPProperty::get_MinRange( THIS_ long FAR *plMinRange )
  4684. {
  4685. HRESULT hr = S_OK;
  4686. if ( !plMinRange )
  4687. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4688. if ( !_fNTDS )
  4689. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4690. hr = get_LONG_Property(this, TEXT("rangeLower"), plMinRange );
  4691. if ( SUCCEEDED(hr) )
  4692. RRETURN(hr);
  4693. if ( _pPropertyInfo == NULL ) // new class
  4694. {
  4695. hr = E_ADS_PROPERTY_NOT_SET;
  4696. RRETURN_EXP_IF_ERR(hr);
  4697. }
  4698. RRETURN_EXP_IF_ERR(hr);
  4699. }
  4700. STDMETHODIMP
  4701. CLDAPProperty::put_MinRange( THIS_ long lMinRange )
  4702. {
  4703. if ( !_fNTDS )
  4704. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4705. HRESULT hr = put_LONG_Property( this, TEXT("rangeLower"),
  4706. lMinRange );
  4707. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4708. {
  4709. _fNTDS = FALSE;
  4710. hr = E_NOTIMPL;
  4711. }
  4712. RRETURN_EXP_IF_ERR(hr);
  4713. }
  4714. STDMETHODIMP
  4715. CLDAPProperty::get_MultiValued( THIS_ VARIANT_BOOL FAR *pfMultiValued )
  4716. {
  4717. if ( !pfMultiValued )
  4718. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  4719. HRESULT hr = S_OK;
  4720. VARIANT_BOOL fSingleValued = FALSE; // by default
  4721. if ( _fNTDS )
  4722. {
  4723. hr = get_VARIANT_BOOL_Property( this, TEXT("isSingleValued"),
  4724. &fSingleValued );
  4725. BAIL_ON_FAILURE(hr);
  4726. }
  4727. else if ( _pPropertyInfo )
  4728. {
  4729. fSingleValued = (VARIANT_BOOL)_pPropertyInfo->fSingleValued;
  4730. }
  4731. *pfMultiValued = fSingleValued? VARIANT_FALSE : VARIANT_TRUE;
  4732. error:
  4733. RRETURN_EXP_IF_ERR(hr);
  4734. }
  4735. STDMETHODIMP
  4736. CLDAPProperty::put_MultiValued( THIS_ VARIANT_BOOL fMultiValued )
  4737. {
  4738. if ( !_fNTDS )
  4739. RRETURN_EXP_IF_ERR( E_NOTIMPL );
  4740. HRESULT hr = put_VARIANT_BOOL_Property( (IADs *) this,
  4741. TEXT("isSingleValued"),
  4742. !fMultiValued );
  4743. if ( hr == E_ADS_CANT_CONVERT_DATATYPE )
  4744. {
  4745. _fNTDS = FALSE;
  4746. hr = E_NOTIMPL;
  4747. }
  4748. RRETURN_EXP_IF_ERR(hr);
  4749. }
  4750. STDMETHODIMP
  4751. CLDAPProperty::Qualifiers(THIS_ IADsCollection FAR* FAR* ppQualifiers)
  4752. {
  4753. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4754. }
  4755. HRESULT
  4756. CLDAPProperty::AllocatePropertyObject(
  4757. CCredentials& Credentials,
  4758. CLDAPProperty FAR * FAR * ppProperty
  4759. )
  4760. {
  4761. CLDAPProperty FAR *pProperty = NULL;
  4762. CAggregatorDispMgr FAR *pDispMgr = NULL;
  4763. CPropertyCache FAR *pPropertyCache = NULL;
  4764. HRESULT hr = S_OK;
  4765. pProperty = new CLDAPProperty();
  4766. if ( pProperty == NULL )
  4767. hr = E_OUTOFMEMORY;
  4768. BAIL_ON_FAILURE(hr);
  4769. pDispMgr = new CAggregatorDispMgr(Credentials);
  4770. if ( pDispMgr == NULL )
  4771. hr = E_OUTOFMEMORY;
  4772. BAIL_ON_FAILURE(hr);
  4773. hr = pDispMgr->LoadTypeInfoEntry(
  4774. LIBID_ADs,
  4775. IID_IADs,
  4776. (IADs *) pProperty,
  4777. DISPID_REGULAR );
  4778. BAIL_ON_FAILURE(hr);
  4779. hr = pDispMgr->LoadTypeInfoEntry(
  4780. LIBID_ADs,
  4781. IID_IADsProperty,
  4782. (IADsProperty *) pProperty,
  4783. DISPID_REGULAR );
  4784. BAIL_ON_FAILURE(hr);
  4785. hr = CPropertyCache::createpropertycache(
  4786. (CCoreADsObject FAR *) pProperty,
  4787. (IGetAttributeSyntax *) pProperty,
  4788. &pPropertyCache
  4789. );
  4790. BAIL_ON_FAILURE(hr);
  4791. pDispMgr->RegisterPropertyCache(pPropertyCache);
  4792. pProperty->_Credentials = Credentials;
  4793. pProperty->_pDispMgr = pDispMgr;
  4794. pProperty->_pPropertyCache = pPropertyCache;
  4795. *ppProperty = pProperty;
  4796. RRETURN(hr);
  4797. error:
  4798. delete pDispMgr;
  4799. delete pProperty;
  4800. RRETURN(hr);
  4801. }
  4802. //
  4803. // Needed for dynamic dispid's in the property cache.
  4804. //
  4805. HRESULT
  4806. CLDAPProperty::GetAttributeSyntax(
  4807. LPWSTR szPropertyName,
  4808. PDWORD pdwSyntaxId
  4809. )
  4810. {
  4811. HRESULT hr;
  4812. hr = LdapGetSyntaxOfAttributeOnServer(
  4813. _pszLDAPServer,
  4814. szPropertyName,
  4815. pdwSyntaxId,
  4816. _Credentials,
  4817. _dwPort
  4818. );
  4819. RRETURN_EXP_IF_ERR(hr);
  4820. }
  4821. /******************************************************************/
  4822. /* Class CLDAPSyntax
  4823. /******************************************************************/
  4824. DEFINE_IDispatch_Implementation(CLDAPSyntax)
  4825. DEFINE_IADs_Implementation(CLDAPSyntax)
  4826. DEFINE_IADsPutGet_UnImplementation(CLDAPSyntax)
  4827. CLDAPSyntax::CLDAPSyntax()
  4828. : _pDispMgr( NULL ),
  4829. _pPropertyCache(NULL)
  4830. {
  4831. ENLIST_TRACKING(CLDAPSyntax);
  4832. }
  4833. CLDAPSyntax::~CLDAPSyntax()
  4834. {
  4835. delete _pDispMgr;
  4836. delete _pPropertyCache;
  4837. }
  4838. HRESULT
  4839. CLDAPSyntax::CreateSyntax(
  4840. BSTR bstrParent,
  4841. SYNTAXINFO *pSyntaxInfo,
  4842. CCredentials& Credentials,
  4843. DWORD dwObjectState,
  4844. REFIID riid,
  4845. void **ppvObj
  4846. )
  4847. {
  4848. CLDAPSyntax FAR *pSyntax = NULL;
  4849. HRESULT hr = S_OK;
  4850. hr = AllocateSyntaxObject(Credentials, &pSyntax );
  4851. BAIL_ON_FAILURE(hr);
  4852. hr = pSyntax->InitializeCoreObject(
  4853. bstrParent,
  4854. pSyntaxInfo->pszName,
  4855. SYNTAX_CLASS_NAME,
  4856. CLSID_LDAPSyntax,
  4857. dwObjectState );
  4858. BAIL_ON_FAILURE(hr);
  4859. pSyntax->_lOleAutoDataType = pSyntaxInfo->lOleAutoDataType;
  4860. //
  4861. // If the call is from umi we need to instantiate the umi object.
  4862. //
  4863. if (Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
  4864. hr = ((CCoreADsObject*)pSyntax)->InitUmiObject(
  4865. IntfPropsSchema,
  4866. pSyntax->_pPropertyCache,
  4867. (IADs *) pSyntax,
  4868. (IADs *) pSyntax,
  4869. riid,
  4870. ppvObj,
  4871. &(pSyntax->_Credentials)
  4872. );
  4873. BAIL_ON_FAILURE(hr);
  4874. //
  4875. // Set the simulated Name property.
  4876. //
  4877. hr = HelperPutStringPropertyInCache(
  4878. L"Name",
  4879. pSyntaxInfo->pszName,
  4880. pSyntax->_Credentials,
  4881. pSyntax->_pPropertyCache
  4882. );
  4883. BAIL_ON_FAILURE(hr);
  4884. RRETURN(S_OK);
  4885. }
  4886. hr = pSyntax->QueryInterface( riid, ppvObj );
  4887. BAIL_ON_FAILURE(hr);
  4888. pSyntax->Release();
  4889. RRETURN(hr);
  4890. error:
  4891. *ppvObj = NULL;
  4892. delete pSyntax;
  4893. RRETURN_EXP_IF_ERR(hr);
  4894. }
  4895. STDMETHODIMP
  4896. CLDAPSyntax::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  4897. {
  4898. if (ppv == NULL) {
  4899. RRETURN(E_POINTER);
  4900. }
  4901. if (IsEqualIID(iid, IID_IUnknown))
  4902. {
  4903. *ppv = (IADs FAR *) this;
  4904. }
  4905. else if (IsEqualIID(iid, IID_IDispatch))
  4906. {
  4907. *ppv = (IADs FAR *) this;
  4908. }
  4909. else if (IsEqualIID(iid, IID_ISupportErrorInfo))
  4910. {
  4911. *ppv = (ISupportErrorInfo FAR *) this;
  4912. }
  4913. else if (IsEqualIID(iid, IID_IADs))
  4914. {
  4915. *ppv = (IADs FAR *) this;
  4916. }
  4917. else if (IsEqualIID(iid, IID_IADsSyntax))
  4918. {
  4919. *ppv = (IADsSyntax FAR *) this;
  4920. }
  4921. else
  4922. {
  4923. *ppv = NULL;
  4924. return E_NOINTERFACE;
  4925. }
  4926. AddRef();
  4927. return NOERROR;
  4928. }
  4929. /* ISupportErrorInfo method */
  4930. STDMETHODIMP
  4931. CLDAPSyntax::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
  4932. {
  4933. if (IsEqualIID(riid, IID_IADs) ||
  4934. IsEqualIID(riid, IID_IADsSyntax)) {
  4935. RRETURN(S_OK);
  4936. } else {
  4937. RRETURN(S_FALSE);
  4938. }
  4939. }
  4940. /* IADs methods */
  4941. STDMETHODIMP
  4942. CLDAPSyntax::SetInfo(THIS)
  4943. {
  4944. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4945. }
  4946. STDMETHODIMP
  4947. CLDAPSyntax::GetInfo(THIS)
  4948. {
  4949. RRETURN(S_OK);
  4950. }
  4951. STDMETHODIMP
  4952. CLDAPSyntax::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
  4953. {
  4954. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  4955. }
  4956. HRESULT
  4957. CLDAPSyntax::AllocateSyntaxObject(
  4958. CCredentials& Credentials,
  4959. CLDAPSyntax FAR * FAR * ppSyntax
  4960. )
  4961. {
  4962. CLDAPSyntax FAR *pSyntax = NULL;
  4963. CAggregatorDispMgr FAR *pDispMgr = NULL;
  4964. CPropertyCache FAR *pPropertyCache = NULL;
  4965. HRESULT hr = S_OK;
  4966. pSyntax = new CLDAPSyntax();
  4967. if ( pSyntax == NULL )
  4968. hr = E_OUTOFMEMORY;
  4969. BAIL_ON_FAILURE(hr);
  4970. pDispMgr = new CAggregatorDispMgr(Credentials);
  4971. if ( pDispMgr == NULL )
  4972. hr = E_OUTOFMEMORY;
  4973. BAIL_ON_FAILURE(hr);
  4974. hr = pDispMgr->LoadTypeInfoEntry(
  4975. LIBID_ADs,
  4976. IID_IADsSyntax,
  4977. (IADsSyntax *) pSyntax,
  4978. DISPID_REGULAR );
  4979. BAIL_ON_FAILURE(hr);
  4980. hr = CPropertyCache::createpropertycache(
  4981. (CCoreADsObject FAR *) pSyntax,
  4982. (IGetAttributeSyntax *) pSyntax,
  4983. &pPropertyCache
  4984. );
  4985. BAIL_ON_FAILURE(hr);
  4986. pSyntax->_pPropertyCache = pPropertyCache;
  4987. pSyntax->_Credentials = Credentials;
  4988. pSyntax->_pDispMgr = pDispMgr;
  4989. *ppSyntax = pSyntax;
  4990. RRETURN(hr);
  4991. error:
  4992. delete pDispMgr;
  4993. delete pSyntax;
  4994. delete pPropertyCache;
  4995. RRETURN_EXP_IF_ERR(hr);
  4996. }
  4997. STDMETHODIMP
  4998. CLDAPSyntax::get_OleAutoDataType( THIS_ long FAR *plOleAutoDataType )
  4999. {
  5000. if ( !plOleAutoDataType )
  5001. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  5002. *plOleAutoDataType = _lOleAutoDataType;
  5003. RRETURN(S_OK);
  5004. }
  5005. STDMETHODIMP
  5006. CLDAPSyntax::put_OleAutoDataType( THIS_ long lOleAutoDataType )
  5007. {
  5008. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  5009. }
  5010. //
  5011. // Needed for dynamic dispid's in the property cache.
  5012. //
  5013. HRESULT
  5014. CLDAPSyntax::GetAttributeSyntax(
  5015. LPWSTR szPropertyName,
  5016. PDWORD pdwSyntaxId
  5017. )
  5018. {
  5019. HRESULT hr = S_OK;
  5020. if ((_Credentials.GetAuthFlags() & ADS_AUTH_RESERVED)
  5021. && !_wcsicmp(L"Name", szPropertyName)) {
  5022. *pdwSyntaxId = LDAPTYPE_CASEIGNORESTRING;
  5023. }
  5024. else {
  5025. hr = E_ADS_PROPERTY_NOT_FOUND;
  5026. }
  5027. RRETURN_EXP_IF_ERR(hr);
  5028. }
  5029. /******************************************************************/
  5030. /* Misc Helpers
  5031. /******************************************************************/
  5032. HRESULT
  5033. MakeVariantFromStringArray(
  5034. BSTR *bstrList,
  5035. VARIANT *pvVariant
  5036. )
  5037. {
  5038. HRESULT hr = S_OK;
  5039. SAFEARRAY *aList = NULL;
  5040. SAFEARRAYBOUND aBound;
  5041. if ( (bstrList != NULL) && (*bstrList != 0) )
  5042. {
  5043. long i = 0;
  5044. long j = 0;
  5045. long nCount = 0;
  5046. while ( bstrList[nCount] )
  5047. nCount++;
  5048. if ( nCount == 1 )
  5049. {
  5050. VariantInit( pvVariant );
  5051. V_VT(pvVariant) = VT_BSTR;
  5052. hr = ADsAllocString( bstrList[0], &(V_BSTR(pvVariant)));
  5053. RRETURN_EXP_IF_ERR(hr);
  5054. }
  5055. aBound.lLbound = 0;
  5056. aBound.cElements = nCount;
  5057. aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
  5058. if ( aList == NULL )
  5059. {
  5060. hr = E_OUTOFMEMORY;
  5061. BAIL_ON_FAILURE(hr);
  5062. }
  5063. i = 0;
  5064. while ( bstrList[i] )
  5065. {
  5066. VARIANT v;
  5067. VariantInit(&v);
  5068. V_VT(&v) = VT_BSTR;
  5069. hr = ADsAllocString( bstrList[i], &(V_BSTR(&v)));
  5070. BAIL_ON_FAILURE(hr);
  5071. hr = SafeArrayPutElement( aList,
  5072. &i,
  5073. &v );
  5074. VariantClear(&v);
  5075. BAIL_ON_FAILURE(hr);
  5076. i++;
  5077. }
  5078. VariantInit( pvVariant );
  5079. V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
  5080. V_ARRAY(pvVariant) = aList;
  5081. }
  5082. else
  5083. {
  5084. aBound.lLbound = 0;
  5085. aBound.cElements = 0;
  5086. aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
  5087. if ( aList == NULL )
  5088. {
  5089. hr = E_OUTOFMEMORY;
  5090. BAIL_ON_FAILURE(hr);
  5091. }
  5092. VariantInit( pvVariant );
  5093. V_VT(pvVariant) = VT_ARRAY | VT_VARIANT;
  5094. V_ARRAY(pvVariant) = aList;
  5095. }
  5096. return S_OK;
  5097. error:
  5098. if ( aList )
  5099. SafeArrayDestroy( aList );
  5100. return hr;
  5101. }
  5102. HRESULT
  5103. MakeVariantFromPropStringTable(
  5104. int *propList,
  5105. LDAP_SCHEMA_HANDLE hSchema,
  5106. VARIANT *pvVariant
  5107. )
  5108. {
  5109. HRESULT hr = S_OK;
  5110. DWORD nCount = 0;
  5111. BSTR *aStrings = NULL;
  5112. if ( propList != NULL )
  5113. {
  5114. while ( propList[nCount] != -1 )
  5115. nCount++;
  5116. }
  5117. if ( nCount > 0 )
  5118. {
  5119. hr = SchemaGetStringsFromStringTable(
  5120. hSchema,
  5121. propList,
  5122. nCount,
  5123. &aStrings );
  5124. if (FAILED(hr))
  5125. RRETURN_EXP_IF_ERR(hr);
  5126. }
  5127. hr = MakeVariantFromStringArray(
  5128. aStrings,
  5129. pvVariant );
  5130. for ( DWORD i = 0; i < nCount; i ++ )
  5131. {
  5132. FreeADsStr( aStrings[i] );
  5133. }
  5134. if (aStrings)
  5135. {
  5136. FreeADsMem( aStrings );
  5137. }
  5138. RRETURN(hr);
  5139. }
  5140. /* No longer needed
  5141. HRESULT
  5142. DeleteSchemaEntry(
  5143. LPTSTR szADsPath,
  5144. LPTSTR szRelativeName,
  5145. LPTSTR szClassName,
  5146. LPTSTR szSubSchemaSubEntry,
  5147. CCredentials& Credentials
  5148. )
  5149. {
  5150. HRESULT hr = S_OK;
  5151. ADS_LDP *ld = NULL;
  5152. TCHAR *pszParentLDAPServer = NULL;
  5153. LPWSTR pszParentLDAPDn = NULL;
  5154. DWORD dwPort = 0;
  5155. LPWSTR pszLDAPDn = NULL;
  5156. LPTSTR *aValues = NULL;
  5157. int nCount = 0;
  5158. //
  5159. // Need to distinguish between LDAP Display Name and ...
  5160. //
  5161. //
  5162. // Get the LDAP server name
  5163. //
  5164. hr = BuildLDAPPathFromADsPath2(
  5165. szADsPath,
  5166. &pszParentLDAPServer,
  5167. &pszParentLDAPDn,
  5168. &dwPort
  5169. );
  5170. BAIL_ON_FAILURE(hr);
  5171. if ( szSubSchemaSubEntry == NULL ) // not NTDS
  5172. {
  5173. hr = E_NOTIMPL;
  5174. BAIL_ON_FAILURE(hr);
  5175. }
  5176. //
  5177. // Get the name of the schema object
  5178. //
  5179. pszLDAPDn = (LPTSTR) AllocADsMem((_tcslen(szRelativeName )
  5180. + _tcslen( _tcschr(szSubSchemaSubEntry,TEXT(',')))
  5181. ) * sizeof(TCHAR)); // includes "\\"
  5182. if ( pszLDAPDn == NULL ){
  5183. hr = E_OUTOFMEMORY;
  5184. BAIL_ON_FAILURE(hr);
  5185. }
  5186. _tcscpy( pszLDAPDn, szRelativeName );
  5187. _tcscat( pszLDAPDn, _tcschr( szSubSchemaSubEntry, TEXT(',')) );
  5188. if ( aValues )
  5189. {
  5190. LdapValueFree( aValues );
  5191. aValues = NULL;
  5192. nCount = 0;
  5193. }
  5194. //
  5195. // Validate the class name first
  5196. //
  5197. hr = LdapReadAttribute(
  5198. pszParentLDAPServer,
  5199. pszLDAPDn,
  5200. TEXT("objectClass"),
  5201. &aValues,
  5202. &nCount,
  5203. Credentials,
  5204. dwPort
  5205. );
  5206. BAIL_ON_FAILURE(hr);
  5207. if ( nCount > 0 )
  5208. {
  5209. if ( _tcsicmp( szClassName, GET_BASE_CLASS( aValues, nCount) ) != 0 )
  5210. {
  5211. hr = E_ADS_BAD_PARAMETER;
  5212. BAIL_ON_FAILURE(hr);
  5213. }
  5214. }
  5215. //
  5216. // Class name has been verified, so delete the object
  5217. //
  5218. hr = LdapDeleteS(
  5219. ld,
  5220. pszLDAPDn
  5221. );
  5222. BAIL_ON_FAILURE(hr);
  5223. error:
  5224. if (pszParentLDAPServer) {
  5225. FreeADsStr(pszParentLDAPServer);
  5226. }
  5227. if (pszParentLDAPDn) {
  5228. FreeADsStr(pszParentLDAPDn);
  5229. }
  5230. if (pszLDAPDn) {
  5231. FreeADsStr(pszLDAPDn);
  5232. }
  5233. if ( aValues ) {
  5234. LdapValueFree( aValues );
  5235. }
  5236. if ( ld ) {
  5237. LdapCloseObject( ld );
  5238. }
  5239. RRETURN(hr);
  5240. }
  5241. */
  5242. //
  5243. // ******** Important usage note **********
  5244. // Users of this function must make sure that cn is part of
  5245. // the list of attributes passed in. This is a requirement and
  5246. // the array must contain a NULL string as the last element.
  5247. // ******** Important usage note **********
  5248. //
  5249. HRESULT
  5250. BuildSchemaLDAPPathAndGetAttribute(
  5251. IN LPTSTR pszParent,
  5252. IN LPTSTR pszName,
  5253. IN LPTSTR pszSubSchemaSubEntry,
  5254. IN BOOL fNew,
  5255. IN CCredentials& Credentials,
  5256. IN LPTSTR pszAttribs[],
  5257. OUT LPWSTR * ppszSchemaLDAPServer,
  5258. OUT LPWSTR * ppszSchemaLDAPDn,
  5259. IN OUT PADS_LDP *ppLd, // optional in,
  5260. OUT PLDAPMessage *ppRes // caller need to get first entry
  5261. )
  5262. {
  5263. HRESULT hr = S_OK;
  5264. LPTSTR pszLDAPServer = NULL;
  5265. LPWSTR pszLDAPDn = NULL;
  5266. DWORD dwPort = 0;
  5267. BOOL fOpenLd = FALSE;
  5268. LPTSTR pszSchemaRoot = NULL;
  5269. LPTSTR pszFilter = NULL; // name on ldap svr
  5270. LDAPMessage *pE = NULL;
  5271. int nCount = 0;
  5272. LPTSTR pszClassName = NULL;
  5273. LPTSTR *aValues = NULL;
  5274. int nNumberOfEntries = 0;
  5275. if ( !ppszSchemaLDAPServer || !ppszSchemaLDAPDn || !ppLd || !ppRes)
  5276. {
  5277. RRETURN(E_ADS_BAD_PARAMETER);
  5278. }
  5279. //
  5280. // Using pszSubSchemaSubEntry to test NTDS is no longer accurate.
  5281. // But the following codes are written to work for NTDS.
  5282. //
  5283. if ( pszSubSchemaSubEntry == NULL ) // not NTDS
  5284. {
  5285. hr = E_NOTIMPL;
  5286. BAIL_IF_ERROR(hr);
  5287. }
  5288. //
  5289. // Get the server name & port #
  5290. //
  5291. hr = BuildLDAPPathFromADsPath2(
  5292. pszParent,
  5293. &pszLDAPServer,
  5294. &pszLDAPDn,
  5295. &dwPort
  5296. );
  5297. BAIL_IF_ERROR(hr);
  5298. //
  5299. // Connect and bind to schema Root object (in NTDS only)
  5300. //
  5301. pszSchemaRoot = _tcschr( // strip CN=Aggregate
  5302. pszSubSchemaSubEntry,
  5303. TEXT(',')
  5304. );
  5305. if ( *ppLd == NULL )
  5306. {
  5307. hr = LdapOpenObject(
  5308. pszLDAPServer,
  5309. pszSchemaRoot+1, // go past ",", we've stripped CN=Aggregate
  5310. ppLd,
  5311. Credentials,
  5312. dwPort
  5313. );
  5314. BAIL_IF_ERROR(hr);
  5315. fOpenLd = TRUE;
  5316. }
  5317. //
  5318. // Set Serach Filter to (& (lDAPDisplayName=<pszName>)
  5319. // (! (isDefunct=TRUE) )
  5320. // )
  5321. //
  5322. pszFilter = (LPTSTR) AllocADsMem((_tcslen(BEGIN_FILTER) + _tcslen(pszName) + _tcslen(END_FILTER) + 1)*sizeof(TCHAR));
  5323. if(!pszFilter)
  5324. {
  5325. hr = E_OUTOFMEMORY;
  5326. BAIL_IF_ERROR(hr);
  5327. }
  5328. _tcscpy( pszFilter, BEGIN_FILTER);
  5329. _tcscat( pszFilter, pszName );
  5330. _tcscat( pszFilter, END_FILTER );
  5331. //
  5332. // Search for scheam pszName (class object) under schema root
  5333. //
  5334. hr = LdapSearchS(
  5335. *ppLd,
  5336. pszSchemaRoot+1, // go past ",", we've stripped CN=Aggregate
  5337. LDAP_SCOPE_ONELEVEL,
  5338. pszFilter,
  5339. pszAttribs,
  5340. 0,
  5341. ppRes
  5342. );
  5343. //
  5344. // Confirm with anoopa & johnsona (ntds5) :
  5345. // If 1 out of the 2 attributes asked for is not on the svr,
  5346. // LdapSearchS (ldap_search_s) returns the 1 located and hr = S_OK
  5347. //
  5348. BAIL_IF_ERROR(hr);
  5349. //
  5350. // Only one active entry should be returned.
  5351. // If more than one entry is returned, return E_ADS_SCHEMA_VIOLATION
  5352. // Get cn to build schemalLDAPDn
  5353. //
  5354. nNumberOfEntries = LdapCountEntries( *ppLd, *ppRes );
  5355. if ( nNumberOfEntries != 1 )
  5356. BAIL_IF_ERROR(hr = E_ADS_SCHEMA_VIOLATION);
  5357. if ( fNew) // ? still keep this
  5358. {
  5359. pszClassName = pszName;
  5360. }
  5361. else
  5362. {
  5363. hr = LdapFirstEntry(
  5364. *ppLd,
  5365. *ppRes,
  5366. &pE
  5367. );
  5368. BAIL_IF_ERROR(hr);
  5369. hr = LdapGetValues(
  5370. *ppLd,
  5371. pE,
  5372. L"cn",
  5373. &aValues,
  5374. &nCount
  5375. );
  5376. BAIL_IF_ERROR(hr);
  5377. if (nCount == 0)
  5378. {
  5379. // use lDAPDisplayName as common name (cn) if cn not set on svr
  5380. pszClassName = pszName;
  5381. }
  5382. else
  5383. {
  5384. pszClassName = aValues[0];
  5385. }
  5386. }
  5387. if (pszLDAPServer!=NULL)
  5388. {
  5389. *ppszSchemaLDAPServer = (LPWSTR) AllocADsStr(
  5390. pszLDAPServer
  5391. );
  5392. if (*ppszSchemaLDAPServer == NULL)
  5393. {
  5394. hr = E_OUTOFMEMORY;
  5395. BAIL_IF_ERROR(hr);
  5396. }
  5397. }
  5398. else // pszLDAPServer allowed to be NULL
  5399. {
  5400. *ppszSchemaLDAPServer = NULL;
  5401. }
  5402. *ppszSchemaLDAPDn = (LPWSTR) AllocADsMem(
  5403. (_tcslen(L"CN=") +
  5404. _tcslen(pszClassName) +
  5405. _tcslen(pszSchemaRoot) + 1 ) *
  5406. sizeof(TCHAR)
  5407. );
  5408. if ( *ppszSchemaLDAPDn == NULL )
  5409. {
  5410. hr = E_OUTOFMEMORY;
  5411. BAIL_IF_ERROR(hr);
  5412. }
  5413. _tcscpy( *ppszSchemaLDAPDn, L"CN=");
  5414. _tcscat( *ppszSchemaLDAPDn, pszClassName );
  5415. _tcscat( *ppszSchemaLDAPDn, pszSchemaRoot );
  5416. //
  5417. // clean up for both success and failure
  5418. //
  5419. release:
  5420. if ( pszLDAPServer )
  5421. FreeADsStr( pszLDAPServer );
  5422. if (pszLDAPDn) {
  5423. FreeADsMem( pszLDAPDn );
  5424. }
  5425. if ( aValues )
  5426. LdapValueFree( aValues );
  5427. if(pszFilter) {
  5428. FreeADsMem(pszFilter);
  5429. pszFilter = NULL;
  5430. }
  5431. RRETURN(hr);
  5432. cleanup:
  5433. //
  5434. // clean up if failure only
  5435. //
  5436. if (fOpenLd==TRUE) {
  5437. LdapCloseObject(*ppLd);
  5438. *ppLd= NULL;
  5439. }
  5440. if (*ppRes) {
  5441. LdapMsgFree(*ppRes);
  5442. *ppRes=NULL;
  5443. }
  5444. if (*ppszSchemaLDAPServer) {
  5445. FreeADsStr(*ppszSchemaLDAPServer);
  5446. *ppszSchemaLDAPServer=NULL;
  5447. }
  5448. if (*ppszSchemaLDAPDn) {
  5449. FreeADsMem(*ppszSchemaLDAPDn);
  5450. *ppszSchemaLDAPDn=NULL;
  5451. }
  5452. goto release;
  5453. }
  5454. HRESULT
  5455. BuildSchemaLDAPPath(
  5456. LPTSTR pszParent,
  5457. LPTSTR pszName,
  5458. LPTSTR pszSubSchemaSubEntry,
  5459. LPWSTR * ppszSchemaLDAPServer,
  5460. LPWSTR * ppszSchemaLDAPDn,
  5461. BOOL fNew,
  5462. ADS_LDP **pld,
  5463. CCredentials& Credentials
  5464. )
  5465. {
  5466. HRESULT hr = S_OK;
  5467. LPTSTR *aValues = NULL;
  5468. LPTSTR *aValues2 = NULL;
  5469. int nCount = 0;
  5470. TCHAR* pszFilter = NULL;
  5471. LPTSTR aStrings[2];
  5472. LDAPMessage *res = NULL;
  5473. LDAPMessage *e = NULL;
  5474. LPTSTR pszLDAPServer = NULL;
  5475. LPWSTR pszLDAPDn = NULL;
  5476. DWORD dwPort = 0;
  5477. LPTSTR pszSchemaRoot = NULL;
  5478. LPTSTR pszClassName = NULL;
  5479. //
  5480. // Get the server name
  5481. //
  5482. hr = BuildLDAPPathFromADsPath2(
  5483. pszParent,
  5484. &pszLDAPServer,
  5485. &pszLDAPDn,
  5486. &dwPort
  5487. );
  5488. BAIL_IF_ERROR(hr);
  5489. if ( pszSubSchemaSubEntry == NULL ) // not NTDS
  5490. {
  5491. hr = E_NOTIMPL;
  5492. BAIL_IF_ERROR(hr);
  5493. }
  5494. // the _tcschr is to get rid of "CN=Aggregate"
  5495. pszSchemaRoot = _tcschr(pszSubSchemaSubEntry, TEXT(','));
  5496. if ( fNew )
  5497. {
  5498. pszClassName = pszName;
  5499. }
  5500. else
  5501. {
  5502. pszFilter = (LPTSTR) AllocADsMem((_tcslen(TEXT("lDAPDisplayName=")) + _tcslen(pszName) + 1)*sizeof(TCHAR));
  5503. if(!pszFilter)
  5504. {
  5505. hr = E_OUTOFMEMORY;
  5506. BAIL_IF_ERROR(hr);
  5507. }
  5508. _tcscpy(pszFilter, TEXT("lDAPDisplayName="));
  5509. _tcscat( pszFilter, pszName );
  5510. aStrings[0] = TEXT("cn");
  5511. aStrings[1] = NULL;
  5512. if ( *pld == NULL )
  5513. {
  5514. hr = LdapOpenObject(
  5515. pszLDAPServer,
  5516. pszSchemaRoot + 1, // go past the , - we've stripped off "CN=Aggregate"
  5517. pld,
  5518. Credentials,
  5519. dwPort
  5520. );
  5521. BAIL_IF_ERROR(hr);
  5522. }
  5523. hr = LdapSearchS(
  5524. *pld,
  5525. pszSchemaRoot + 1,
  5526. LDAP_SCOPE_ONELEVEL,
  5527. pszFilter,
  5528. aStrings,
  5529. 0,
  5530. &res
  5531. );
  5532. // Only one entry should be returned
  5533. if (FAILED(hr)
  5534. || (FAILED(hr = LdapFirstEntry( *pld, res, &e )))
  5535. || (FAILED(hr = LdapGetValues( *pld, e, aStrings[0], &aValues2, &nCount)))
  5536. )
  5537. {
  5538. BAIL_IF_ERROR(hr);
  5539. }
  5540. if ( nCount == 0 )
  5541. pszClassName = pszName;
  5542. else
  5543. pszClassName = aValues2[0];
  5544. }
  5545. *ppszSchemaLDAPServer = (LPWSTR)AllocADsStr(pszLDAPServer);
  5546. //
  5547. // pszLDAPServer might be NULL, in which case NULL is the
  5548. // expected return value from the alloc.
  5549. //
  5550. if ( (*ppszSchemaLDAPServer == NULL) && pszLDAPServer) {
  5551. hr = E_OUTOFMEMORY;
  5552. BAIL_IF_ERROR(hr);
  5553. }
  5554. *ppszSchemaLDAPDn = (LPTSTR) AllocADsMem(
  5555. (_tcslen(L"CN=") +
  5556. _tcslen(pszClassName) +
  5557. _tcslen(pszSchemaRoot) + 1 ) *
  5558. sizeof(TCHAR));
  5559. if ( *ppszSchemaLDAPDn == NULL )
  5560. {
  5561. hr = E_OUTOFMEMORY;
  5562. BAIL_IF_ERROR(hr);
  5563. }
  5564. _tcscpy( *ppszSchemaLDAPDn, L"CN=");
  5565. _tcscat( *ppszSchemaLDAPDn, pszClassName );
  5566. _tcscat( *ppszSchemaLDAPDn, pszSchemaRoot );
  5567. cleanup:
  5568. if ( aValues )
  5569. LdapValueFree( aValues );
  5570. if ( aValues2 )
  5571. LdapValueFree( aValues2 );
  5572. if ( pszLDAPServer )
  5573. FreeADsStr( pszLDAPServer );
  5574. if (pszLDAPDn) {
  5575. FreeADsStr( pszLDAPDn);
  5576. }
  5577. if ( res )
  5578. LdapMsgFree( res );
  5579. if(pszFilter)
  5580. {
  5581. FreeADsMem(pszFilter);
  5582. pszFilter = NULL;
  5583. }
  5584. RRETURN(hr);
  5585. }
  5586. HRESULT
  5587. MakePropArrayFromVariant(
  5588. VARIANT vProp,
  5589. SCHEMAINFO *hSchema,
  5590. int **pOIDs,
  5591. DWORD *pnNumOfOids )
  5592. {
  5593. HRESULT hr = S_OK;
  5594. int nIndex;
  5595. LONG dwSLBound;
  5596. LONG dwSUBound;
  5597. LONG i = 0;
  5598. LONG j, k;
  5599. DWORD nCurrent = 0;
  5600. *pOIDs = NULL;
  5601. *pnNumOfOids = 0;
  5602. if ( !V_ISARRAY( &vProp))
  5603. {
  5604. // special case of one object (not an array)
  5605. nIndex = FindSearchTableIndex( V_BSTR(&vProp),
  5606. hSchema->aPropertiesSearchTable,
  5607. hSchema->nNumOfProperties * 2 );
  5608. if ( nIndex != -1 )
  5609. {
  5610. *pOIDs = (int *) AllocADsMem( sizeof(int) * 2);
  5611. if ( *pOIDs == NULL )
  5612. {
  5613. hr = E_OUTOFMEMORY;
  5614. BAIL_ON_FAILURE(hr);
  5615. }
  5616. (*pOIDs)[nCurrent++] = nIndex;
  5617. (*pOIDs)[nCurrent] = -1;
  5618. *pnNumOfOids = 1;
  5619. }
  5620. else
  5621. {
  5622. hr = E_ADS_PROPERTY_NOT_FOUND;
  5623. }
  5624. RRETURN_EXP_IF_ERR(hr);
  5625. }
  5626. //
  5627. // Here, we have an array of properties. We want to create an array of
  5628. // indexes into the aPropertiesSearchTable
  5629. //
  5630. hr = SafeArrayGetLBound(V_ARRAY(&vProp),
  5631. 1,
  5632. (long FAR *)&dwSLBound
  5633. );
  5634. BAIL_ON_FAILURE(hr);
  5635. hr = SafeArrayGetUBound(V_ARRAY(&vProp),
  5636. 1,
  5637. (long FAR *)&dwSUBound
  5638. );
  5639. BAIL_ON_FAILURE(hr);
  5640. *pOIDs = (int *) AllocADsMem( sizeof(int) * (dwSUBound - dwSLBound + 2));
  5641. if ( *pOIDs == NULL )
  5642. {
  5643. hr = E_OUTOFMEMORY;
  5644. BAIL_ON_FAILURE(hr);
  5645. }
  5646. for (i = dwSLBound; i <= dwSUBound; i++) {
  5647. VARIANT v;
  5648. VariantInit(&v);
  5649. hr = SafeArrayGetElement(V_ARRAY(&vProp),
  5650. (long FAR *)&i,
  5651. &v
  5652. );
  5653. BAIL_ON_FAILURE(hr);
  5654. nIndex = FindSearchTableIndex( V_BSTR(&v),
  5655. hSchema->aPropertiesSearchTable,
  5656. hSchema->nNumOfProperties * 2 );
  5657. VariantClear(&v);
  5658. if ( nIndex != -1 )
  5659. {
  5660. (*pOIDs)[nCurrent++] = nIndex;
  5661. }
  5662. else
  5663. {
  5664. hr = E_ADS_PROPERTY_NOT_FOUND;
  5665. BAIL_ON_FAILURE(hr);
  5666. }
  5667. }
  5668. (*pOIDs)[nCurrent] = -1;
  5669. *pnNumOfOids = nCurrent;
  5670. SortAndRemoveDuplicateOIDs( *pOIDs, pnNumOfOids );
  5671. error:
  5672. if (FAILED(hr))
  5673. {
  5674. if ( *pOIDs )
  5675. {
  5676. FreeADsMem( *pOIDs );
  5677. *pOIDs = NULL;
  5678. }
  5679. }
  5680. RRETURN(hr);
  5681. }
  5682. HRESULT
  5683. MakePropArrayFromStringArray(
  5684. LPTSTR *aValues,
  5685. DWORD nCount,
  5686. SCHEMAINFO *hSchema,
  5687. int **pOIDs,
  5688. DWORD *pnNumOfOids
  5689. )
  5690. {
  5691. HRESULT hr = S_OK;
  5692. int nIndex;
  5693. DWORD i = 0;
  5694. DWORD nCurrent = 0;
  5695. *pOIDs = NULL;
  5696. *pnNumOfOids = 0;
  5697. //
  5698. // Here, we have an array of properties. We want to create an array of
  5699. // indexes into the aPropertiesSearchTable
  5700. //
  5701. *pOIDs = (int *) AllocADsMem( sizeof(int) * (nCount+1));
  5702. if ( *pOIDs == NULL )
  5703. {
  5704. hr = E_OUTOFMEMORY;
  5705. BAIL_ON_FAILURE(hr);
  5706. }
  5707. for (i = 0; i < nCount ; i++) {
  5708. nIndex = FindSearchTableIndex( aValues[i],
  5709. hSchema->aPropertiesSearchTable,
  5710. hSchema->nNumOfProperties * 2 );
  5711. if ( nIndex != -1 )
  5712. {
  5713. (*pOIDs)[nCurrent++] = nIndex;
  5714. }
  5715. else
  5716. {
  5717. hr = E_ADS_PROPERTY_NOT_FOUND;
  5718. BAIL_ON_FAILURE(hr);
  5719. }
  5720. }
  5721. (*pOIDs)[nCurrent] = -1;
  5722. *pnNumOfOids = nCurrent;
  5723. qsort( *pOIDs, *pnNumOfOids, sizeof((*pOIDs)[0]), intcmp );
  5724. error:
  5725. if (FAILED(hr))
  5726. {
  5727. if ( *pOIDs )
  5728. {
  5729. FreeADsMem( *pOIDs );
  5730. *pOIDs = NULL;
  5731. }
  5732. }
  5733. RRETURN(hr);
  5734. }
  5735. /******************************************************************/
  5736. /* Misc Schema functions
  5737. /******************************************************************/
  5738. BOOL
  5739. GetLdapClassPrimaryInterface(
  5740. LPTSTR pszLdapClass,
  5741. GUID **ppPrimaryInterfaceGUID,
  5742. GUID **ppCLSID
  5743. )
  5744. {
  5745. for ( int i = 0; i < ARRAY_SIZE(aClassMap); i++ )
  5746. {
  5747. if ( _tcsicmp( pszLdapClass, aClassMap[i].pszLdapClassName ) == 0 )
  5748. {
  5749. *ppPrimaryInterfaceGUID = (GUID *) aClassMap[i].pPrimaryInterfaceGUID;
  5750. *ppCLSID = (GUID *) aClassMap[i].pCLSID;
  5751. return TRUE;
  5752. }
  5753. }
  5754. return FALSE;
  5755. }
  5756. BOOL
  5757. GetPrimaryInterface(
  5758. LPTSTR pszClassName,
  5759. SCHEMAINFO *pSchemaInfo,
  5760. PCLASSNAME_LIST pClassNames,
  5761. GUID **ppPrimaryInterfaceGUID,
  5762. GUID **ppCLSID
  5763. )
  5764. {
  5765. int i = 0;
  5766. CLASSINFO *pClassInfo;
  5767. LPTSTR pszName;
  5768. DWORD index;
  5769. PCLASSNAME_LIST pClass = NULL;
  5770. PCLASSNAME_LIST pNextClass = NULL;
  5771. BOOL fExitStatus = FALSE;
  5772. if ( GetLdapClassPrimaryInterface( pszClassName,
  5773. ppPrimaryInterfaceGUID,
  5774. ppCLSID ))
  5775. {
  5776. return TRUE;
  5777. }
  5778. index = (DWORD) FindEntryInSearchTable(
  5779. pszClassName,
  5780. pSchemaInfo->aClassesSearchTable,
  5781. 2 * pSchemaInfo->nNumOfClasses );
  5782. if ( index == ((DWORD) -1) )
  5783. return FALSE;
  5784. //
  5785. // Recursively search the list of superiors and
  5786. // aux classes. To avoid loops, we maintain a list
  5787. // of classes we have already reached. If we are called
  5788. // with a class on this list, we abort.
  5789. //
  5790. //
  5791. // Make sure the current class isn't already on the list
  5792. //
  5793. if (pClassNames) {
  5794. for (pNextClass = pClassNames;
  5795. pNextClass != NULL;
  5796. pNextClass = pNextClass->pNext)
  5797. {
  5798. if (_tcscmp(pNextClass->pszClassName, pszClassName) == 0)
  5799. {
  5800. // found match, bail
  5801. fExitStatus = FALSE;
  5802. BAIL_ON_SUCCESS(S_OK);
  5803. }
  5804. }
  5805. }
  5806. //
  5807. // Construct a node for the current class & add it to the list
  5808. //
  5809. pClass = static_cast<PCLASSNAME_LIST>(AllocADsMem(sizeof(CLASSNAME_LIST)));
  5810. if (!pClass) {
  5811. BAIL_ON_FAILURE(E_OUTOFMEMORY);
  5812. }
  5813. pClass->pszClassName = static_cast<LPTSTR>(AllocADsMem((_tcslen(pszClassName)+1) * sizeof(TCHAR)));
  5814. if (!pClass->pszClassName) {
  5815. BAIL_ON_FAILURE(E_OUTOFMEMORY);
  5816. }
  5817. _tcscpy(pClass->pszClassName, pszClassName);
  5818. pClass->pNext = pClassNames;
  5819. //
  5820. // Perform the recursive search
  5821. //
  5822. pClassInfo = &(pSchemaInfo->aClasses[index]);
  5823. if ( pClassInfo->pOIDsSuperiorClasses )
  5824. {
  5825. for ( i = 0;
  5826. (pszName = pClassInfo->pOIDsSuperiorClasses[i]);
  5827. i++ )
  5828. {
  5829. if ( GetPrimaryInterface( pszName, pSchemaInfo, pClass,
  5830. ppPrimaryInterfaceGUID, ppCLSID ))
  5831. {
  5832. fExitStatus = TRUE;
  5833. BAIL_ON_SUCCESS(S_OK);
  5834. }
  5835. }
  5836. }
  5837. if ( pClassInfo->pOIDsAuxClasses )
  5838. {
  5839. for ( i = 0;
  5840. (pszName = pClassInfo->pOIDsAuxClasses[i]);
  5841. i++ )
  5842. {
  5843. if ( GetPrimaryInterface( pszName, pSchemaInfo, pClass,
  5844. ppPrimaryInterfaceGUID, ppCLSID ))
  5845. {
  5846. fExitStatus = TRUE;
  5847. BAIL_ON_SUCCESS(S_OK);
  5848. }
  5849. }
  5850. }
  5851. error:
  5852. //
  5853. // Each level of recursion is responsible for freeing
  5854. // its own corresponding node.
  5855. //
  5856. if (pClass) {
  5857. if (pClass->pszClassName) {
  5858. FreeADsMem(pClass->pszClassName);
  5859. }
  5860. FreeADsMem(pClass);
  5861. }
  5862. return fExitStatus;
  5863. }
  5864. HRESULT
  5865. SchemaGetPrimaryInterface(
  5866. LDAP_SCHEMA_HANDLE hSchema,
  5867. LPTSTR pszClassName,
  5868. GUID **ppPrimaryInterfaceGUID,
  5869. GUID **ppCLSID
  5870. )
  5871. {
  5872. HRESULT hr = S_OK;
  5873. SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
  5874. if ( !pSchemaInfo )
  5875. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  5876. GetPrimaryInterface(
  5877. pszClassName,
  5878. pSchemaInfo,
  5879. NULL,
  5880. ppPrimaryInterfaceGUID,
  5881. ppCLSID );
  5882. RRETURN(hr);
  5883. }
  5884. BOOL
  5885. MapLdapClassToADsClass(
  5886. LPTSTR *aLdapClasses,
  5887. int nCount,
  5888. LPTSTR pszADsClass
  5889. )
  5890. {
  5891. *pszADsClass = 0;
  5892. if ( nCount == 0 )
  5893. return FALSE;
  5894. if ( _tcsicmp( aLdapClasses[nCount-1], TEXT("Top")) == 0 )
  5895. {
  5896. for ( int j = 0; j < nCount; j++ )
  5897. {
  5898. LPTSTR pszLdapClass = aLdapClasses[j];
  5899. for ( int i = 0; i < ARRAY_SIZE(aClassMap); i++ )
  5900. {
  5901. if ( _tcsicmp( pszLdapClass, aClassMap[i].pszLdapClassName ) == 0 )
  5902. {
  5903. _tcscpy( pszADsClass, aClassMap[i].pszADsClassName );
  5904. return TRUE;
  5905. }
  5906. }
  5907. }
  5908. _tcscpy( pszADsClass, aLdapClasses[0] );
  5909. return FALSE;
  5910. }
  5911. else
  5912. {
  5913. for ( int j = nCount-1; j >= 0; j-- )
  5914. {
  5915. LPTSTR pszLdapClass = aLdapClasses[j];
  5916. for ( int i = 0; i < ARRAY_SIZE(aClassMap); i++ )
  5917. {
  5918. if ( _tcsicmp( pszLdapClass, aClassMap[i].pszLdapClassName ) == 0 )
  5919. {
  5920. _tcscpy( pszADsClass, aClassMap[i].pszADsClassName );
  5921. return TRUE;
  5922. }
  5923. }
  5924. }
  5925. _tcscpy( pszADsClass, aLdapClasses[nCount-1] );
  5926. return FALSE;
  5927. }
  5928. }
  5929. BOOL
  5930. MapLdapClassToADsClass(
  5931. LPTSTR pszClassName,
  5932. LDAP_SCHEMA_HANDLE hSchema,
  5933. LPTSTR pszADsClass
  5934. )
  5935. {
  5936. LPTSTR aClasses[1];
  5937. CLASSINFO *pClassInfo = NULL;
  5938. SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
  5939. *pszADsClass = 0;
  5940. aClasses[0] = pszClassName;
  5941. if ( MapLdapClassToADsClass( aClasses, 1, pszADsClass ))
  5942. return TRUE;
  5943. DWORD index = (DWORD) FindEntryInSearchTable(
  5944. pszClassName,
  5945. pSchemaInfo->aClassesSearchTable,
  5946. 2 * pSchemaInfo->nNumOfClasses );
  5947. if ( index == ((DWORD) -1) ) // cannot find the class name in the schema
  5948. {
  5949. _tcscpy( pszADsClass, pszClassName );
  5950. return FALSE;
  5951. }
  5952. pClassInfo = &(pSchemaInfo->aClasses[index]);
  5953. if ( pClassInfo->pOIDsSuperiorClasses )
  5954. {
  5955. LPTSTR pszName = NULL;
  5956. for ( int i = 0;
  5957. (pszName = pClassInfo->pOIDsSuperiorClasses[i]);
  5958. i++ )
  5959. {
  5960. if ( MapLdapClassToADsClass( pszName, pSchemaInfo, pszADsClass))
  5961. return TRUE;
  5962. }
  5963. }
  5964. _tcscpy( pszADsClass, pszClassName );
  5965. return FALSE;
  5966. }
  5967. LPTSTR
  5968. MapADsClassToLdapClass(
  5969. LPTSTR pszADsClass,
  5970. LPTSTR pszLdapClass
  5971. )
  5972. {
  5973. for ( int i=0; i < ARRAY_SIZE(aClassMap); i++ )
  5974. {
  5975. if ( _tcsicmp( pszADsClass, aClassMap[i].pszADsClassName ) == 0 )
  5976. {
  5977. _tcscpy( pszLdapClass, aClassMap[i].pszLdapClassName );
  5978. return pszLdapClass;
  5979. }
  5980. }
  5981. _tcscpy( pszLdapClass, pszADsClass );
  5982. return pszLdapClass;
  5983. }
  5984. STDMETHODIMP
  5985. makeUnionVariantFromLdapObjects(
  5986. LDAPOBJECTARRAY ldapSrcObjects1,
  5987. LDAPOBJECTARRAY ldapSrcObjects2,
  5988. VARIANT FAR * pvPossSuperiors
  5989. )
  5990. {
  5991. HRESULT hr = S_OK;
  5992. BSTR *retVals = NULL;
  5993. DWORD dwNumVals = 0;
  5994. BSTR curString = NULL;
  5995. DWORD dwMaxVals = 0;
  5996. DWORD dwCtr = 0;
  5997. DWORD dwArrIndx = 0;
  5998. PLDAPOBJECT pLdapObject;
  5999. dwMaxVals = ldapSrcObjects1.dwCount + ldapSrcObjects2.dwCount + 1;
  6000. retVals = (BSTR *)AllocADsMem(dwMaxVals * sizeof(BSTR *));
  6001. if (!retVals) {
  6002. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  6003. }
  6004. for (dwCtr = 0; dwCtr < ldapSrcObjects1.dwCount; dwCtr++) {
  6005. pLdapObject = ldapSrcObjects1.pLdapObjects + dwCtr;
  6006. curString = LDAPOBJECT_STRING(pLdapObject);
  6007. hr = addStringIfAbsent(curString, retVals, &dwArrIndx);
  6008. BAIL_ON_FAILURE(hr);
  6009. }
  6010. for (dwCtr = 0; dwCtr < ldapSrcObjects2.dwCount; dwCtr++) {
  6011. pLdapObject = ldapSrcObjects2.pLdapObjects + dwCtr;
  6012. curString = LDAPOBJECT_STRING(pLdapObject);
  6013. hr = addStringIfAbsent(curString, retVals, &dwArrIndx);
  6014. BAIL_ON_FAILURE(hr);
  6015. }
  6016. // do the same for the second ldapobjectarray
  6017. hr = MakeVariantFromStringArray(retVals, pvPossSuperiors);
  6018. error:
  6019. // clean up the string array either way
  6020. for (dwCtr=0; dwCtr < dwArrIndx; dwCtr++) {
  6021. ADsFreeString(retVals[dwCtr]);
  6022. }
  6023. FreeADsMem(retVals);
  6024. RRETURN(hr);
  6025. }
  6026. STDMETHODIMP
  6027. addStringIfAbsent(
  6028. BSTR addString,
  6029. BSTR *strArray,
  6030. PDWORD dwArrIndx
  6031. )
  6032. {
  6033. HRESULT hr = S_OK;
  6034. DWORD dwCtr = 0;
  6035. BOOLEAN fFound = FALSE;
  6036. for (dwCtr = 0; (dwCtr < *dwArrIndx) && !fFound; dwCtr ++) {
  6037. if (!_wcsicmp(addString, strArray[dwCtr])) {
  6038. fFound = TRUE;
  6039. }
  6040. }
  6041. if (!fFound) {
  6042. hr = ADsAllocString(
  6043. addString,
  6044. &strArray[*dwArrIndx]
  6045. );
  6046. BAIL_ON_FAILURE(hr);
  6047. (*dwArrIndx)++;
  6048. strArray[*dwArrIndx] = NULL;
  6049. }
  6050. error:
  6051. RRETURN(hr);
  6052. }