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.

1348 lines
34 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: attribute.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #include "common.h"
  12. #include "attr.h"
  13. ///////////////////////////////////////////////////////////////////////////
  14. // CADSIAttribute
  15. CADSIAttribute::CADSIAttribute(ADS_ATTR_INFO* pInfo, BOOL bMulti, PCWSTR pszSyntax, BOOL bReadOnly)
  16. {
  17. m_pAttrInfo = pInfo;
  18. m_bDirty = FALSE;
  19. m_bMulti = bMulti;
  20. m_bReadOnly = bReadOnly;
  21. m_bSet = FALSE;
  22. m_bMandatory = FALSE;
  23. m_szSyntax = pszSyntax;
  24. PWSTR pwz = wcsrchr(pInfo->pszAttrName, L';');
  25. if (pwz)
  26. {
  27. pwz; // move past the hyphen to the range end value.
  28. ASSERT(*pwz);
  29. *pwz=L'\0';
  30. }
  31. }
  32. CADSIAttribute::CADSIAttribute(PADS_ATTR_INFO pInfo)
  33. {
  34. //
  35. // REVIEW_JEFFJON : these need to be updated with correct values
  36. //
  37. m_pAttrInfo = pInfo;
  38. m_bDirty = FALSE;
  39. m_bMulti = FALSE;
  40. m_bReadOnly = FALSE;
  41. m_bSet = FALSE;
  42. m_bMandatory = FALSE;
  43. PWSTR pwz = wcsrchr(pInfo->pszAttrName, L';');
  44. if (pwz)
  45. {
  46. pwz; // move past the hyphen to the range end value.
  47. ASSERT(*pwz);
  48. *pwz=L'\0';
  49. }
  50. }
  51. // NTRAID#NTBUG9-552796-2002/02/21-artm Constant string parm written to in constructor.
  52. // Probably need to change the signature to reflect how the parameter is used.
  53. CADSIAttribute::CADSIAttribute(const CString& attributeName)
  54. {
  55. m_pAttrInfo = new ADS_ATTR_INFO;
  56. memset(m_pAttrInfo, 0, sizeof(ADS_ATTR_INFO));
  57. // Find the token in the attribute name that precedes the range of attributes.
  58. // If we find the token, we need to truncate the attribute name at that
  59. // point to omit the range.
  60. CString name;
  61. int position = attributeName.Find(L';');
  62. if (position > -1)
  63. {
  64. name = attributeName.Left(position);
  65. }
  66. else
  67. {
  68. name = attributeName;
  69. }
  70. _AllocString(name, &(m_pAttrInfo->pszAttrName) );
  71. m_bMulti = FALSE;
  72. m_bDirty = FALSE;
  73. m_bReadOnly = FALSE;
  74. m_bSet = FALSE;
  75. m_bMandatory = FALSE;
  76. }
  77. CADSIAttribute::CADSIAttribute(CADSIAttribute* pOldAttr)
  78. {
  79. m_pAttrInfo = NULL;
  80. ADS_ATTR_INFO* pAttrInfo = pOldAttr->GetAttrInfo();
  81. // These copies are done separately because there are places
  82. // that I need to copy only the ADsAttrInfo and not the values
  83. //
  84. _CopyADsAttrInfo(pAttrInfo, &m_pAttrInfo);
  85. _CopyADsValues(pAttrInfo, m_pAttrInfo );
  86. m_bReadOnly = FALSE;
  87. m_bMulti = pOldAttr->m_bMulti;
  88. m_bDirty = pOldAttr->m_bDirty;
  89. m_szSyntax = pOldAttr->m_szSyntax;
  90. }
  91. CADSIAttribute::~CADSIAttribute()
  92. {
  93. if (!m_bReadOnly)
  94. {
  95. _FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
  96. }
  97. }
  98. ADSVALUE* CADSIAttribute::GetADSVALUE(int idx)
  99. {
  100. return &(m_pAttrInfo->pADsValues[idx]);
  101. }
  102. HRESULT CADSIAttribute::SetValues(PADSVALUE pADsValue, DWORD dwNumValues)
  103. {
  104. HRESULT hr = S_OK;
  105. ADS_ATTR_INFO* pNewAttrInfo = NULL;
  106. if (!_CopyADsAttrInfo(m_pAttrInfo, &pNewAttrInfo))
  107. {
  108. return E_FAIL;
  109. }
  110. pNewAttrInfo->dwNumValues = dwNumValues;
  111. pNewAttrInfo->pADsValues = pADsValue;
  112. if (pADsValue == NULL)
  113. {
  114. pNewAttrInfo->dwControlCode = ADS_ATTR_CLEAR;
  115. }
  116. else
  117. {
  118. pNewAttrInfo->dwADsType = pADsValue->dwType;
  119. }
  120. //
  121. // Free the old one and swap in the new one
  122. //
  123. if (!m_bReadOnly)
  124. {
  125. _FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
  126. }
  127. m_pAttrInfo = pNewAttrInfo;
  128. m_bReadOnly = FALSE;
  129. return hr;
  130. }
  131. // Pre: this function only called when server returns a range of the values
  132. // for a multivalued attribute
  133. //
  134. HRESULT CADSIAttribute::AppendValues(PADSVALUE pADsValue, DWORD dwNumValues)
  135. {
  136. HRESULT hr = S_OK;
  137. ADS_ATTR_INFO* pNewAttrInfo = NULL;
  138. if (!_CopyADsAttrInfo(m_pAttrInfo, &pNewAttrInfo))
  139. {
  140. return E_OUTOFMEMORY;
  141. }
  142. DWORD newValueCount = m_pAttrInfo->dwNumValues + dwNumValues;
  143. pNewAttrInfo->dwNumValues = newValueCount;
  144. if (newValueCount == 0)
  145. {
  146. pNewAttrInfo->pADsValues = 0;
  147. pNewAttrInfo->dwControlCode = ADS_ATTR_CLEAR;
  148. }
  149. else
  150. {
  151. pNewAttrInfo->pADsValues = new ADSVALUE[newValueCount];
  152. if (pNewAttrInfo->pADsValues == NULL)
  153. {
  154. // NOTICE-NTRAID#NTBUG9-552904-2002/02/21-artm Leaks memory from pNewAttrInfo.
  155. // Memory was allocated by _CopyADsAttrInfo(), never freed following
  156. // this path of execution.
  157. // Fixed by calling _FreeADsAttrInfo().
  158. CADSIAttribute::_FreeADsAttrInfo(pNewAttrInfo);
  159. return E_OUTOFMEMORY;
  160. }
  161. else
  162. {
  163. ZeroMemory(pNewAttrInfo->pADsValues, newValueCount * sizeof(ADSVALUE));
  164. pNewAttrInfo->dwADsType = pADsValue->dwType;
  165. // NTRAID#NTBUG9-720957-2002/10/15-artm do deep copy of ADsValues
  166. // Copy in the old values
  167. ADSVALUE* oldValues = m_pAttrInfo->pADsValues;
  168. ADSVALUE* copiedValues = pNewAttrInfo->pADsValues;
  169. const DWORD numOldValues = m_pAttrInfo->dwNumValues;
  170. hr = S_OK;
  171. for (DWORD i = 0; i < numOldValues && SUCCEEDED(hr); ++i)
  172. {
  173. hr = _CloneADsValue(oldValues[i], copiedValues[i]);
  174. }
  175. if (FAILED(hr))
  176. {
  177. // Unable to copy old values to new attribute;
  178. // free new attribute and leave the old one intact.
  179. // Since new attribute was not allocated by ADSI, always
  180. // pass FALSE for read only flag.
  181. CADSIAttribute::_FreeADsAttrInfo(&pNewAttrInfo, FALSE);
  182. return hr;
  183. }
  184. oldValues = NULL; // get rid of alias
  185. // Copy in the new values
  186. // Set copiedValues to point to the next open value after all the old values.
  187. copiedValues = copiedValues + numOldValues;
  188. hr = S_OK;
  189. for (DWORD i = 0; i < dwNumValues && SUCCEEDED(hr); ++i)
  190. {
  191. hr = _CloneADsValue(pADsValue[i], copiedValues[i]);
  192. }
  193. if (FAILED(hr))
  194. {
  195. // Unable to copy appended values to new attribute;
  196. // free new attribute and leave the old one intact.
  197. // Since new attribute was not allocated by ADSI, always
  198. // pass FALSE for read only flag.
  199. CADSIAttribute::_FreeADsAttrInfo(&pNewAttrInfo, FALSE);
  200. return hr;
  201. }
  202. copiedValues = NULL; // get rid of alias
  203. }
  204. }
  205. //
  206. // Free the old one and swap in the new one
  207. //
  208. // NOTICE-2002/10/16-artm
  209. //
  210. // N.B. - attributes marked 'read only' just mean that the attribute information
  211. // pointer was allocated by ADSI (and not us). This means that when it is
  212. // freed it needs to be done with FreeADsMem(). Equally important, the pointer
  213. // in the attribute is actually an alias to memory contained in an array of
  214. // information for all the returned attributes. The "master" list pointer is
  215. // stored by the property page UI (search for SaveOptionalValuesPointer() and
  216. // SaveMandatoryValuesPointer() ), and it is this pointer that owns the memory.
  217. // Freeing the alias stored in the attribute wrapper class gives you bad karma,
  218. // so don't do it.
  219. if (!m_bReadOnly)
  220. {
  221. CADSIAttribute::_FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
  222. }
  223. // NOTICE-NTRAID#NTBUG9-552904-2002/02/22-artm Memory leak if attribute list is marked read only.
  224. // This looks like a leak since the pointer is reassigned without freeing the memory.
  225. // Perhaps the problem lies in updating a read only attribute...
  226. //
  227. // UPDATE: see note above; this is not a leak
  228. m_pAttrInfo = pNewAttrInfo;
  229. // m_bReadOnly is used to mark the attribute as having been allocated either by ADSI or
  230. // by this tool . . . the method of memory allocation differs and needs to be kept track
  231. // of for when it needs to be freed. Regardless of whether or not the attribute was
  232. // read only at the beginning of the call, it needs to be marked FALSE now since the
  233. // memory for pNewAttrInfo was allocatd by the tool.
  234. m_bReadOnly = FALSE;
  235. return hr;
  236. }
  237. HRESULT CADSIAttribute::SetValues(const CStringList& sValues)
  238. {
  239. HRESULT hr = S_OK;
  240. ADS_ATTR_INFO* pNewAttrInfo = NULL;
  241. if (!_CopyADsAttrInfo(m_pAttrInfo, &pNewAttrInfo))
  242. {
  243. return E_FAIL;
  244. }
  245. int iCount = sValues.GetCount();
  246. pNewAttrInfo->dwNumValues = iCount;
  247. if (!_AllocValues(&pNewAttrInfo->pADsValues, iCount))
  248. {
  249. return E_FAIL;
  250. }
  251. int idx = 0;
  252. POSITION pos = sValues.GetHeadPosition();
  253. while (pos != NULL)
  254. {
  255. CString s = sValues.GetNext(pos);
  256. ADSVALUE* pADsValue = &(pNewAttrInfo->pADsValues[idx]);
  257. ASSERT(pADsValue != NULL);
  258. hr = _SetADsFromString(
  259. s,
  260. pNewAttrInfo->dwADsType,
  261. pADsValue
  262. );
  263. if (FAILED(hr))
  264. {
  265. _FreeADsAttrInfo(&pNewAttrInfo, FALSE);
  266. return hr;
  267. }
  268. idx++;
  269. }
  270. // Free the old one and swap in the new one
  271. //
  272. _FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
  273. m_pAttrInfo = pNewAttrInfo;
  274. m_bReadOnly = FALSE;
  275. return hr;
  276. }
  277. void CADSIAttribute::GetValues(CStringList& sValues, DWORD dwMaxCharCount)
  278. {
  279. GetStringFromADs(m_pAttrInfo, sValues, dwMaxCharCount);
  280. }
  281. ADS_ATTR_INFO* CADSIAttribute::GetAttrInfo()
  282. {
  283. return m_pAttrInfo;
  284. }
  285. ////////////////////////////////////////////////////////////////////////
  286. // Public Helper Functions
  287. ///////////////////////////////////////////////////////////////////////
  288. HRESULT CADSIAttribute::SetValuesInDS(CAttrList2* ptouchedAttr, IDirectoryObject* pDirObject)
  289. {
  290. DWORD dwReturn;
  291. DWORD dwAttrCount = 0;
  292. ADS_ATTR_INFO* pAttrInfo;
  293. pAttrInfo = new ADS_ATTR_INFO[ptouchedAttr->GetCount()];
  294. CADSIAttribute* pCurrentAttr;
  295. POSITION pos = ptouchedAttr->GetHeadPosition();
  296. while(pos != NULL)
  297. {
  298. ptouchedAttr->GetNextDirty(pos, &pCurrentAttr);
  299. if (pCurrentAttr != NULL)
  300. {
  301. ADS_ATTR_INFO* pCurrentAttrInfo = pCurrentAttr->GetAttrInfo();
  302. ADS_ATTR_INFO* pNewAttrInfo = &pAttrInfo[dwAttrCount];
  303. if (!_CopyADsAttrInfo(pCurrentAttrInfo, pNewAttrInfo))
  304. {
  305. for (DWORD itr = 0; itr < dwAttrCount; itr++)
  306. {
  307. _FreeADsAttrInfo(&pAttrInfo[itr]);
  308. }
  309. delete[] pAttrInfo;
  310. pAttrInfo = NULL;
  311. return E_FAIL;
  312. }
  313. if (!_CopyADsValues(pCurrentAttrInfo, pNewAttrInfo))
  314. {
  315. delete[] pAttrInfo;
  316. pAttrInfo = NULL;
  317. return E_FAIL;
  318. }
  319. if (pAttrInfo[dwAttrCount].dwNumValues == 0)
  320. {
  321. pAttrInfo[dwAttrCount].dwControlCode = ADS_ATTR_CLEAR;
  322. }
  323. else
  324. {
  325. pAttrInfo[dwAttrCount].dwControlCode = ADS_ATTR_UPDATE;
  326. }
  327. dwAttrCount++;
  328. }
  329. }
  330. // Commit the changes that have been made to the ADSI cache
  331. //
  332. HRESULT hr = pDirObject->SetObjectAttributes(pAttrInfo, dwAttrCount, &dwReturn);
  333. for (DWORD itr = 0; itr < dwAttrCount; itr++)
  334. {
  335. _FreeADsAttrInfo(&pAttrInfo[itr]);
  336. }
  337. delete[] pAttrInfo;
  338. pAttrInfo = NULL;
  339. return hr;
  340. }
  341. /////////////////////////////////////////////////////////////////////////
  342. // Private Helper Functions
  343. ////////////////////////////////////////////////////////////////////////
  344. // NOTICE-2002/02/25-artm _SetADsFromString() w/in trust boundary
  345. // Pre: lpszValue != NULL && lpszValue is a zero terminated string
  346. HRESULT CADSIAttribute::_SetADsFromString(LPCWSTR lpszValue, ADSTYPE adsType, ADSVALUE* pADsValue)
  347. {
  348. HRESULT hr = E_FAIL;
  349. if ( adsType == ADSTYPE_INVALID )
  350. {
  351. return hr;
  352. }
  353. pADsValue->dwType = adsType;
  354. switch( adsType )
  355. {
  356. case ADSTYPE_DN_STRING :
  357. if (!_AllocString(lpszValue, &pADsValue->DNString))
  358. {
  359. return E_FAIL;
  360. }
  361. hr = S_OK;
  362. break;
  363. case ADSTYPE_CASE_EXACT_STRING :
  364. if (!_AllocString(lpszValue, &pADsValue->CaseExactString))
  365. {
  366. return E_FAIL;
  367. }
  368. hr = S_OK;
  369. break;
  370. case ADSTYPE_CASE_IGNORE_STRING :
  371. if (!_AllocString(lpszValue, &pADsValue->CaseIgnoreString))
  372. {
  373. return E_FAIL;
  374. }
  375. hr = S_OK;
  376. break;
  377. case ADSTYPE_PRINTABLE_STRING :
  378. if (!_AllocString(lpszValue, &pADsValue->PrintableString))
  379. {
  380. return E_FAIL;
  381. }
  382. hr = S_OK;
  383. break;
  384. case ADSTYPE_NUMERIC_STRING :
  385. if (!_AllocString(lpszValue, &pADsValue->NumericString))
  386. {
  387. return E_FAIL;
  388. }
  389. hr = S_OK;
  390. break;
  391. case ADSTYPE_OBJECT_CLASS :
  392. if (!_AllocString(lpszValue, &pADsValue->ClassName))
  393. {
  394. return E_FAIL;
  395. }
  396. hr = S_OK;
  397. break;
  398. case ADSTYPE_BOOLEAN :
  399. // FUTURE-2002/02/22-artm Use constants for literal strings, and use
  400. // a function to determine their length. Easier to maintain, read, and
  401. // less error prone. If performance is a concern, calculate the lengths
  402. // once and assign to length constants.
  403. // NOTICE-2002/02/25-artm lpszValue must be null terminated
  404. // This requirement is currently met by the functions that call
  405. // this helper.
  406. if (_wcsnicmp(lpszValue, L"TRUE", 4) == 0)
  407. {
  408. (DWORD)pADsValue->Boolean = TRUE;
  409. }
  410. else if (_wcsnicmp(lpszValue, L"FALSE", 5) == 0)
  411. {
  412. (DWORD)pADsValue->Boolean = FALSE;
  413. }
  414. else
  415. {
  416. return E_FAIL;
  417. }
  418. hr = S_OK;
  419. break;
  420. case ADSTYPE_INTEGER :
  421. int value;
  422. // As long as lpszValue is a valid string (even empty string is okay),
  423. // swscanf will convert the number from a string to an int.
  424. value = swscanf(lpszValue, L"%ld", &pADsValue->Integer);
  425. if (value > 0)
  426. {
  427. hr = S_OK;
  428. }
  429. else
  430. {
  431. hr = E_FAIL;
  432. }
  433. break;
  434. case ADSTYPE_OCTET_STRING :
  435. {
  436. hr = HexStringToByteArray_0x(
  437. lpszValue,
  438. &( pADsValue->OctetString.lpValue ),
  439. pADsValue->OctetString.dwLength);
  440. // Should never happen.
  441. ASSERT (hr != E_POINTER);
  442. }
  443. break;
  444. case ADSTYPE_LARGE_INTEGER :
  445. wtoli(lpszValue, pADsValue->LargeInteger);
  446. hr = S_OK;
  447. break;
  448. case ADSTYPE_UTC_TIME :
  449. int iNum;
  450. WORD n;
  451. // NOTICE-2002/02/25-artm Validates that input string by
  452. // checking that all 6 time fields were filled in. Relies
  453. // on input string being null terminated (okay as long as
  454. // function contract met).
  455. iNum = swscanf(lpszValue, L"%02d/%02d/%04d %02d:%02d:%02d",
  456. &n,
  457. &pADsValue->UTCTime.wDay,
  458. &pADsValue->UTCTime.wYear,
  459. &pADsValue->UTCTime.wHour,
  460. &pADsValue->UTCTime.wMinute,
  461. &pADsValue->UTCTime.wSecond
  462. );
  463. pADsValue->UTCTime.wMonth = n;
  464. // This strange conversion is done so that the DayOfWeek will be set in
  465. // the UTCTime. By converting it to a filetime it ignores the dayofweek but
  466. // converting back fills it in.
  467. //
  468. FILETIME ft;
  469. SystemTimeToFileTime(&pADsValue->UTCTime, &ft);
  470. FileTimeToSystemTime(&ft, &pADsValue->UTCTime);
  471. if (iNum == 6)
  472. {
  473. hr = S_OK;
  474. }
  475. else
  476. {
  477. hr = E_FAIL;
  478. }
  479. break;
  480. default :
  481. break;
  482. }
  483. return hr;
  484. }
  485. // Copies the old octet string to the new octet string. Any memory allocated
  486. // to the new octet string will be freed first (and will be freed even if the
  487. // copy failed).
  488. BOOL
  489. CADSIAttribute::_AllocOctetString(
  490. const ADS_OCTET_STRING& rOldOctetString,
  491. ADS_OCTET_STRING& rNew)
  492. {
  493. _FreeOctetString(rNew.lpValue);
  494. int iLength = rOldOctetString.dwLength;
  495. rNew.dwLength = iLength;
  496. rNew.lpValue = new BYTE[iLength];
  497. if (rNew.lpValue == NULL)
  498. {
  499. // FUTURE-2002/02/25-artm Unnecessary function call.
  500. // Calling _FreeOctetString() does nothing here since
  501. // we can only get to this code branch if the allocation
  502. // failed.
  503. _FreeOctetString(rNew.lpValue);
  504. return FALSE;
  505. }
  506. memcpy(rNew.lpValue, rOldOctetString.lpValue, iLength);
  507. return TRUE;
  508. }
  509. void CADSIAttribute::_FreeOctetString(BYTE*& lpValue)
  510. {
  511. if (lpValue != NULL)
  512. {
  513. // NOTICE-NTRAID#NTBUG9-554582-2002/02/25-artm Memory leak b/c lpValue allocated with [].
  514. // Code should be delete [] lpValue.
  515. delete [] lpValue;
  516. lpValue = NULL;
  517. }
  518. }
  519. // NOTICE-2002/02/25-artm lpsz must be a null terminated string
  520. BOOL CADSIAttribute::_AllocString(LPCWSTR lpsz, LPWSTR* lppszNew)
  521. {
  522. _FreeString(lppszNew);
  523. int iLength = wcslen(lpsz);
  524. *lppszNew = new WCHAR[iLength + 1]; // an extra for the NULL
  525. if (*lppszNew == NULL)
  526. {
  527. // FUTURE-2002/02/25-artm Unnecessary function call.
  528. // Calling _FreeString() does nothing here since
  529. // we can only get to this code branch if the allocation
  530. // failed.
  531. _FreeString(lppszNew);
  532. return FALSE;
  533. }
  534. // This is a legitimate use of wcscpy() since the destination buffer
  535. // is sized large enought to hold the src and terminating null. It
  536. // hinges on the fact that the source string is null terminated.
  537. wcscpy(*lppszNew, lpsz);
  538. return TRUE;
  539. }
  540. void CADSIAttribute::_FreeString(LPWSTR* lppsz)
  541. {
  542. if (*lppsz != NULL)
  543. {
  544. // NOTICE-NTRAID#NTBUG9-554582-2002/02/25-artm Memory leak b/c lppsz allocated with [].
  545. // Code should be delete [] lppsz.
  546. delete [] *lppsz;
  547. }
  548. *lppsz = NULL;
  549. }
  550. BOOL CADSIAttribute::_AllocValues(ADSVALUE** ppValues, DWORD dwLength)
  551. {
  552. _FreeADsValues(ppValues, dwLength);
  553. *ppValues = new ADSVALUE[dwLength];
  554. if (*ppValues == NULL)
  555. {
  556. // FUTURE-2002/02/25-artm Unnecessary function call.
  557. // Calling _FreeADsValues() does nothing here since
  558. // we can only get to this code branch if the allocation
  559. // failed.
  560. _FreeADsValues(ppValues, dwLength);
  561. return FALSE;
  562. }
  563. memset(*ppValues, 0, sizeof(ADSVALUE) * dwLength);
  564. return TRUE;
  565. }
  566. BOOL CADSIAttribute::_CopyADsValues(ADS_ATTR_INFO* pOldAttrInfo, ADS_ATTR_INFO* pNewAttrInfo)
  567. {
  568. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  569. pNewAttrInfo->dwNumValues = pOldAttrInfo->dwNumValues;
  570. if (!_AllocValues(&pNewAttrInfo->pADsValues, pOldAttrInfo->dwNumValues))
  571. {
  572. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  573. return FALSE;
  574. }
  575. HRESULT hr = S_OK;
  576. for (DWORD itr = 0; itr < pOldAttrInfo->dwNumValues && SUCCEEDED(hr); itr++)
  577. {
  578. hr = _CloneADsValue(pOldAttrInfo->pADsValues[itr], pNewAttrInfo->pADsValues[itr]);
  579. }
  580. if (FAILED(hr))
  581. {
  582. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  583. return FALSE;
  584. }
  585. return TRUE;
  586. }
  587. void CADSIAttribute::_FreeADsValues(ADSVALUE** ppADsValues, DWORD dwLength)
  588. {
  589. if (NULL == ppADsValues)
  590. {
  591. // Caller is making a mistake.
  592. ASSERT(false);
  593. return;
  594. }
  595. ADSVALUE* values = *ppADsValues;
  596. if (NULL == values)
  597. {
  598. // Don't assert, legal to free a null pointer.
  599. // Logically, this means there are no values set.
  600. return;
  601. }
  602. for (DWORD idx = 0; idx < dwLength; idx++)
  603. {
  604. _FreeADsValue(values[idx]);
  605. }
  606. delete [] values;
  607. *ppADsValues = NULL;
  608. }
  609. // The values are not copied here. They must be copied after the ADS_ATTR_INFO
  610. // is copied by using _CopyADsValues()
  611. //
  612. BOOL CADSIAttribute::_CopyADsAttrInfo(ADS_ATTR_INFO* pAttrInfo, ADS_ATTR_INFO** ppNewAttrInfo)
  613. {
  614. _FreeADsAttrInfo(ppNewAttrInfo, FALSE);
  615. *ppNewAttrInfo = new ADS_ATTR_INFO;
  616. if (*ppNewAttrInfo == NULL)
  617. {
  618. return FALSE;
  619. }
  620. memset(*ppNewAttrInfo, 0, sizeof(ADS_ATTR_INFO));
  621. BOOL bReturn = _AllocString(pAttrInfo->pszAttrName, &((*ppNewAttrInfo)->pszAttrName));
  622. if (!bReturn)
  623. {
  624. _FreeADsAttrInfo(ppNewAttrInfo, FALSE);
  625. return FALSE;
  626. }
  627. (*ppNewAttrInfo)->dwADsType = pAttrInfo->dwADsType;
  628. (*ppNewAttrInfo)->dwControlCode = pAttrInfo->dwControlCode;
  629. (*ppNewAttrInfo)->dwNumValues = pAttrInfo->dwNumValues;
  630. return TRUE;
  631. }
  632. BOOL CADSIAttribute::_CopyADsAttrInfo(ADS_ATTR_INFO* pAttrInfo, ADS_ATTR_INFO* pNewAttrInfo)
  633. {
  634. memset(pNewAttrInfo, 0, sizeof(ADS_ATTR_INFO));
  635. BOOL bReturn = _AllocString(pAttrInfo->pszAttrName, &pNewAttrInfo->pszAttrName);
  636. if (!bReturn)
  637. {
  638. return FALSE;
  639. }
  640. pNewAttrInfo->dwADsType = pAttrInfo->dwADsType;
  641. pNewAttrInfo->dwControlCode = pAttrInfo->dwControlCode;
  642. pNewAttrInfo->dwNumValues = pAttrInfo->dwNumValues;
  643. return TRUE;
  644. }
  645. void CADSIAttribute::_FreeADsAttrInfo(ADS_ATTR_INFO** ppAttrInfo, BOOL bReadOnly)
  646. {
  647. if (*ppAttrInfo == NULL)
  648. {
  649. return;
  650. }
  651. if (!bReadOnly)
  652. {
  653. _FreeString(&(*ppAttrInfo)->pszAttrName);
  654. _FreeADsValues(&(*ppAttrInfo)->pADsValues, (*ppAttrInfo)->dwNumValues);
  655. delete *ppAttrInfo;
  656. }
  657. else
  658. {
  659. FreeADsMem(*ppAttrInfo);
  660. }
  661. *ppAttrInfo = NULL;
  662. }
  663. void CADSIAttribute::_FreeADsAttrInfo(ADS_ATTR_INFO* pAttrInfo)
  664. {
  665. if (pAttrInfo == NULL)
  666. {
  667. return;
  668. }
  669. _FreeString(&pAttrInfo->pszAttrName);
  670. _FreeADsValues(&pAttrInfo->pADsValues, pAttrInfo->dwNumValues);
  671. }
  672. //
  673. // _CloneADsValue():
  674. //
  675. // Makes a deep copy of a single ADSVALUE (allocating memory as needed).
  676. // These cloned values should be freed using _FreeADsValue().
  677. //
  678. // Returns S_OK on success, S_FALSE if atribute type not supported,
  679. // error code otherwise.
  680. //
  681. HRESULT
  682. CADSIAttribute::_CloneADsValue(const ADSVALUE& original, ADSVALUE& clone)
  683. {
  684. HRESULT hr = S_OK;
  685. // Make sure we are copying to a clean slate (wouldn't want a mutant clone).
  686. ::ZeroMemory(&clone, sizeof(clone));
  687. // Copy the type of the value.
  688. clone.dwType = original.dwType;
  689. // Copy the data in the value.
  690. switch (clone.dwType)
  691. {
  692. case ADSTYPE_INVALID :
  693. // Might indicate a bug . . .
  694. ASSERT(false);
  695. // . . . but the copy was successful.
  696. hr = S_OK;
  697. break;
  698. case ADSTYPE_DN_STRING :
  699. if (! _AllocString(original.DNString, &(clone.DNString)) )
  700. {
  701. hr = E_OUTOFMEMORY;
  702. }
  703. break;
  704. case ADSTYPE_CASE_EXACT_STRING :
  705. if (! _AllocString(original.CaseExactString, &(clone.CaseExactString)) )
  706. {
  707. hr = E_OUTOFMEMORY;
  708. }
  709. break;
  710. case ADSTYPE_CASE_IGNORE_STRING :
  711. if (! _AllocString(original.CaseIgnoreString, &(clone.CaseIgnoreString)) )
  712. {
  713. hr = E_OUTOFMEMORY;
  714. }
  715. break;
  716. case ADSTYPE_PRINTABLE_STRING :
  717. if (! _AllocString(original.PrintableString, &(clone.PrintableString)) )
  718. {
  719. hr = E_OUTOFMEMORY;
  720. }
  721. break;
  722. case ADSTYPE_NUMERIC_STRING :
  723. if (! _AllocString(original.NumericString, &(clone.NumericString)) )
  724. {
  725. hr = E_OUTOFMEMORY;
  726. }
  727. break;
  728. case ADSTYPE_BOOLEAN :
  729. clone.Boolean = original.Boolean;
  730. break;
  731. case ADSTYPE_INTEGER :
  732. clone.Integer = original.Integer;
  733. break;
  734. case ADSTYPE_OCTET_STRING :
  735. if (! _AllocOctetString(original.OctetString, clone.OctetString) )
  736. {
  737. hr = E_OUTOFMEMORY;
  738. }
  739. break;
  740. case ADSTYPE_UTC_TIME :
  741. clone.UTCTime = original.UTCTime;
  742. break;
  743. case ADSTYPE_LARGE_INTEGER :
  744. clone.LargeInteger = original.LargeInteger;
  745. break;
  746. case ADSTYPE_OBJECT_CLASS :
  747. if (! _AllocString(original.ClassName, &(clone.ClassName)) )
  748. {
  749. hr = E_OUTOFMEMORY;
  750. }
  751. break;
  752. case ADSTYPE_PROV_SPECIFIC :
  753. if ( !_CloneProviderSpecificBlob(original.ProviderSpecific, clone.ProviderSpecific) )
  754. {
  755. hr = E_OUTOFMEMORY;
  756. }
  757. break;
  758. case ADSTYPE_CASEIGNORE_LIST :
  759. case ADSTYPE_OCTET_LIST :
  760. case ADSTYPE_PATH :
  761. case ADSTYPE_POSTALADDRESS :
  762. case ADSTYPE_TIMESTAMP :
  763. case ADSTYPE_BACKLINK :
  764. case ADSTYPE_TYPEDNAME :
  765. case ADSTYPE_HOLD :
  766. case ADSTYPE_NETADDRESS :
  767. case ADSTYPE_REPLICAPOINTER :
  768. case ADSTYPE_FAXNUMBER :
  769. case ADSTYPE_EMAIL :
  770. // NDS attributes not supported in ADSI Edit
  771. ASSERT(false);
  772. hr = S_FALSE;
  773. break;
  774. case ADSTYPE_NT_SECURITY_DESCRIPTOR :
  775. if (! _CloneNtSecurityDescriptor(original.SecurityDescriptor, clone.SecurityDescriptor) )
  776. {
  777. hr = E_OUTOFMEMORY;
  778. }
  779. break;
  780. case ADSTYPE_UNKNOWN :
  781. // Can't copy data that we don't know how to interpret.
  782. ASSERT(false);
  783. hr = S_FALSE;
  784. break;
  785. case ADSTYPE_DN_WITH_BINARY :
  786. if (! _CloneDNWithBinary(original.pDNWithBinary, clone.pDNWithBinary) )
  787. {
  788. hr = E_OUTOFMEMORY;
  789. }
  790. break;
  791. case ADSTYPE_DN_WITH_STRING :
  792. if (! _CloneDNWithString(original.pDNWithString, clone.pDNWithString) )
  793. {
  794. hr = E_OUTOFMEMORY;
  795. }
  796. break;
  797. default :
  798. // Unexpected data type.
  799. ASSERT(false);
  800. hr = E_UNEXPECTED;
  801. break;
  802. }
  803. if (FAILED(hr))
  804. {
  805. _FreeADsValue(clone);
  806. }
  807. return hr;
  808. }
  809. void
  810. CADSIAttribute::_FreeADsValue(ADSVALUE& value)
  811. {
  812. switch(value.dwType)
  813. {
  814. case ADSTYPE_DN_STRING :
  815. _FreeString( &(value.DNString) );
  816. break;
  817. case ADSTYPE_CASE_EXACT_STRING :
  818. _FreeString( &(value.CaseExactString) );
  819. break;
  820. case ADSTYPE_CASE_IGNORE_STRING :
  821. _FreeString( &(value.CaseIgnoreString) );
  822. break;
  823. case ADSTYPE_PRINTABLE_STRING :
  824. _FreeString( &(value.PrintableString) );
  825. break;
  826. case ADSTYPE_NUMERIC_STRING :
  827. _FreeString( &(value.NumericString) );
  828. break;
  829. case ADSTYPE_INVALID :
  830. case ADSTYPE_BOOLEAN :
  831. case ADSTYPE_INTEGER :
  832. case ADSTYPE_UTC_TIME :
  833. case ADSTYPE_LARGE_INTEGER :
  834. // Nothing to do, done.
  835. break;
  836. case ADSTYPE_OCTET_STRING :
  837. _FreeOctetString( value.OctetString.lpValue );
  838. break;
  839. case ADSTYPE_OBJECT_CLASS :
  840. _FreeString( &(value.ClassName) );
  841. break;
  842. case ADSTYPE_PROV_SPECIFIC :
  843. _FreeProviderSpecificBlob(value.ProviderSpecific);
  844. break;
  845. case ADSTYPE_CASEIGNORE_LIST :
  846. case ADSTYPE_OCTET_LIST :
  847. case ADSTYPE_PATH :
  848. case ADSTYPE_POSTALADDRESS :
  849. case ADSTYPE_TIMESTAMP :
  850. case ADSTYPE_BACKLINK :
  851. case ADSTYPE_TYPEDNAME :
  852. case ADSTYPE_HOLD :
  853. case ADSTYPE_NETADDRESS :
  854. case ADSTYPE_REPLICAPOINTER :
  855. case ADSTYPE_FAXNUMBER :
  856. case ADSTYPE_EMAIL :
  857. // NDS attributes not supported in ADSI Edit
  858. ASSERT(false);
  859. break;
  860. case ADSTYPE_NT_SECURITY_DESCRIPTOR :
  861. _FreeNtSecurityDescriptor(value.SecurityDescriptor);
  862. break;
  863. case ADSTYPE_UNKNOWN :
  864. // Can't free it if we don't know how to interpret it.
  865. ASSERT(false);
  866. break;
  867. case ADSTYPE_DN_WITH_BINARY :
  868. _FreeDNWithBinary(value.pDNWithBinary);
  869. break;
  870. case ADSTYPE_DN_WITH_STRING :
  871. _FreeDNWithString(value.pDNWithString);
  872. break;
  873. default :
  874. // Unexpected data type.
  875. ASSERT(false);
  876. break;
  877. }
  878. // Zero out the ADS value to make it obvious if it is accidentally
  879. // reused.
  880. ::ZeroMemory(&value, sizeof(value));
  881. }
  882. ///////////////////////////////////////////////////////////////////////////
  883. // CAttrList2
  884. // NOTICE-2002/02/25-artm lpszAttr needs to be null terminated
  885. POSITION CAttrList2::FindProperty(LPCWSTR lpszAttr)
  886. {
  887. CADSIAttribute* pAttr;
  888. for (POSITION p = GetHeadPosition(); p != NULL; GetNext(p))
  889. {
  890. // I use GetAt here because I don't want to advance the POSITION
  891. // because it is returned if they are equal
  892. //
  893. pAttr = GetAt(p);
  894. CString sName;
  895. pAttr->GetProperty(sName);
  896. // NOTICE-2002/02/25-artm Both strings should be null terminated.
  897. // sName is already in a data structure, so it should be null terminated
  898. if (wcscmp(sName, lpszAttr) == 0)
  899. {
  900. break;
  901. }
  902. }
  903. return p;
  904. }
  905. BOOL CAttrList2::HasProperty(LPCWSTR lpszAttr)
  906. {
  907. POSITION pos = FindProperty(lpszAttr);
  908. return pos != NULL;
  909. }
  910. // Searches through the cache for the attribute
  911. // ppAttr will point to the CADSIAttribute if found, NULL if not
  912. //
  913. void CAttrList2::GetNextDirty(POSITION& pos, CADSIAttribute** ppAttr)
  914. {
  915. *ppAttr = GetNext(pos);
  916. if (pos == NULL && !(*ppAttr)->IsDirty())
  917. {
  918. *ppAttr = NULL;
  919. return;
  920. }
  921. while (!(*ppAttr)->IsDirty() && pos != NULL)
  922. {
  923. *ppAttr = GetNext(pos);
  924. if (!(*ppAttr)->IsDirty() && pos == NULL)
  925. {
  926. *ppAttr = NULL;
  927. break;
  928. }
  929. }
  930. }
  931. BOOL CAttrList2::HasDirty()
  932. {
  933. POSITION pos = GetHeadPosition();
  934. while (pos != NULL)
  935. {
  936. CADSIAttribute* pAttr = GetNext(pos);
  937. if (pAttr->IsDirty())
  938. {
  939. return TRUE;
  940. }
  941. }
  942. return FALSE;
  943. }
  944. ///////////////////////////////////////////////////////////////////////////
  945. // Implementation of helper functions.
  946. bool
  947. CADSIAttribute::_CloneBlob(
  948. const BYTE* src,
  949. DWORD srcSize,
  950. BYTE*& dest,
  951. DWORD& destSize)
  952. {
  953. bool success = true;
  954. ASSERT(dest == NULL);
  955. _FreeBlob(dest, destSize);
  956. destSize = srcSize;
  957. if (srcSize > 0 && src != NULL)
  958. {
  959. dest = new BYTE[destSize];
  960. if (NULL != dest)
  961. {
  962. memcpy(dest, src, srcSize * sizeof(BYTE));
  963. }
  964. else
  965. {
  966. destSize = 0;
  967. success = false;
  968. }
  969. }
  970. else
  971. {
  972. // Both better be true, else we were called incorrectly.
  973. ASSERT(srcSize == 0);
  974. ASSERT(src == NULL);
  975. dest = NULL;
  976. destSize = 0;
  977. }
  978. return success;
  979. }
  980. void
  981. CADSIAttribute::_FreeBlob(BYTE*& blob, DWORD& blobSize)
  982. {
  983. if (blob != NULL)
  984. {
  985. ASSERT(blobSize > 0);
  986. delete [] blob;
  987. blob = NULL;
  988. }
  989. blobSize = 0;
  990. }
  991. bool
  992. CADSIAttribute::_CloneProviderSpecificBlob(
  993. const ADS_PROV_SPECIFIC& src,
  994. ADS_PROV_SPECIFIC& dest)
  995. {
  996. bool success = true;
  997. success = _CloneBlob(src.lpValue, src.dwLength, dest.lpValue, dest.dwLength);
  998. return success;
  999. }
  1000. void
  1001. CADSIAttribute::_FreeProviderSpecificBlob(ADS_PROV_SPECIFIC& blob)
  1002. {
  1003. _FreeBlob(blob.lpValue, blob.dwLength);
  1004. }
  1005. bool
  1006. CADSIAttribute::_CloneNtSecurityDescriptor(
  1007. const ADS_NT_SECURITY_DESCRIPTOR& src,
  1008. ADS_NT_SECURITY_DESCRIPTOR& dest)
  1009. {
  1010. bool success = true;
  1011. success = _CloneBlob(src.lpValue, src.dwLength, dest.lpValue, dest.dwLength);
  1012. return success;
  1013. }
  1014. void
  1015. CADSIAttribute::_FreeNtSecurityDescriptor(ADS_NT_SECURITY_DESCRIPTOR& sd)
  1016. {
  1017. _FreeBlob(sd.lpValue, sd.dwLength);
  1018. }
  1019. bool
  1020. CADSIAttribute::_CloneDNWithBinary(
  1021. const PADS_DN_WITH_BINARY& src,
  1022. PADS_DN_WITH_BINARY& dest)
  1023. {
  1024. bool success = true;
  1025. // Validate parameters.
  1026. ASSERT(dest == NULL);
  1027. if (src == NULL)
  1028. {
  1029. dest = NULL;
  1030. return true;
  1031. }
  1032. dest = new ADS_DN_WITH_BINARY;
  1033. if (!dest)
  1034. {
  1035. // out of memory
  1036. return false;
  1037. }
  1038. ::ZeroMemory(dest, sizeof(ADS_DN_WITH_BINARY));
  1039. // Copy the GUID.
  1040. success = _CloneBlob(
  1041. src->lpBinaryValue,
  1042. src->dwLength,
  1043. dest->lpBinaryValue,
  1044. dest->dwLength);
  1045. // Copy the distinguished name if GUID copy succeeded.
  1046. if (success)
  1047. {
  1048. success = _AllocString(src->pszDNString, &(dest->pszDNString) ) != FALSE;
  1049. }
  1050. // If any part of copying failed, make sure we aren't leaking any memory.
  1051. if (!success)
  1052. {
  1053. _FreeDNWithBinary(dest);
  1054. }
  1055. return success;
  1056. }
  1057. void
  1058. CADSIAttribute::_FreeDNWithBinary(PADS_DN_WITH_BINARY& dn)
  1059. {
  1060. _FreeBlob(dn->lpBinaryValue, dn->dwLength);
  1061. _FreeString( &(dn->pszDNString) );
  1062. dn = NULL;
  1063. }
  1064. bool
  1065. CADSIAttribute::_CloneDNWithString(
  1066. const PADS_DN_WITH_STRING& src,
  1067. PADS_DN_WITH_STRING& dest)
  1068. {
  1069. bool success = true;
  1070. // Validate parameters.
  1071. ASSERT(dest == NULL);
  1072. if (src == NULL)
  1073. {
  1074. dest = NULL;
  1075. return true;
  1076. }
  1077. dest = new ADS_DN_WITH_STRING;
  1078. if (!dest)
  1079. {
  1080. // out of memory
  1081. return false;
  1082. }
  1083. ::ZeroMemory(dest, sizeof(ADS_DN_WITH_BINARY));
  1084. // Copy the associated string.
  1085. success = _AllocString(src->pszStringValue, &(dest->pszStringValue) ) != FALSE;
  1086. // Copy the distinguished name if associated string copy succeeded.
  1087. if (success)
  1088. {
  1089. success = _AllocString(src->pszDNString, &(dest->pszDNString) ) != FALSE;
  1090. }
  1091. // Don't leak memory if any part of copy failed.
  1092. if (!success)
  1093. {
  1094. _FreeDNWithString(dest);
  1095. }
  1096. return success;
  1097. }
  1098. void
  1099. CADSIAttribute::_FreeDNWithString(PADS_DN_WITH_STRING& dn)
  1100. {
  1101. _FreeString( &(dn->pszStringValue) );
  1102. _FreeString( &(dn->pszDNString) );
  1103. dn = NULL;
  1104. }