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.

726 lines
22 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 <SnapBase.h>
  12. #include "common.h"
  13. #include "attredit.h"
  14. #include "attribute.h"
  15. #ifdef DEBUG_ALLOCATOR
  16. #ifdef _DEBUG
  17. #define new DEBUG_NEW
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21. #endif
  22. ///////////////////////////////////////////////////////////////////////////
  23. // CADSIAttr
  24. CADSIAttr::CADSIAttr(ADS_ATTR_INFO* pInfo, BOOL bMulti, PCWSTR pszSyntax, BOOL bReadOnly)
  25. {
  26. m_pAttrInfo = pInfo;
  27. m_bDirty = FALSE;
  28. m_bMulti = bMulti;
  29. m_bReadOnly = bReadOnly;
  30. m_szSyntax = pszSyntax;
  31. PWSTR pwz = wcsrchr(pInfo->pszAttrName, L';');
  32. if (pwz)
  33. {
  34. pwz; // move past the hyphen to the range end value.
  35. ASSERT(*pwz);
  36. *pwz=L'\0';
  37. }
  38. }
  39. // NTRAID#NTBUG9-552796-2002/02/21-artm Constant string parm written to in constructor.
  40. // Probably need to change the signature to reflect how the parameter is used.
  41. CADSIAttr::CADSIAttr(LPCWSTR lpszAttr)
  42. {
  43. m_pAttrInfo = new ADS_ATTR_INFO;
  44. memset(m_pAttrInfo, 0, sizeof(ADS_ATTR_INFO));
  45. PWSTR pwz = wcsrchr(lpszAttr, L';');
  46. if (pwz)
  47. {
  48. // FUTURE-2002/02/22-artm This line of code does not appear to do anything.
  49. // Consider removing upon review.
  50. pwz; // move past the hyphen to the range end value.
  51. // FUTURE-2002/02/22-artm Code is unnecessarily confusing.
  52. // The assert is checking that the temporary pointer is not pointing
  53. // to the zero termination character at the end. On the other hand, the
  54. // code then proceeds to set that character to NULL! I suspect that there
  55. // is no need to have the ASSERT(); if there is, then this code needs to be revisited.
  56. ASSERT(*pwz);
  57. *pwz=L'\0';
  58. }
  59. _AllocString(lpszAttr, &(m_pAttrInfo->pszAttrName));
  60. m_bMulti = FALSE;
  61. m_bDirty = FALSE;
  62. m_bReadOnly = FALSE;
  63. }
  64. CADSIAttr::CADSIAttr(CADSIAttr* pOldAttr)
  65. {
  66. m_pAttrInfo = NULL;
  67. ADS_ATTR_INFO* pAttrInfo = pOldAttr->GetAttrInfo();
  68. // These copies are done separately because there are places
  69. // that I need to copy only the ADsAttrInfo and not the values
  70. //
  71. _CopyADsAttrInfo(pAttrInfo, &m_pAttrInfo);
  72. _CopyADsValues(pAttrInfo, m_pAttrInfo );
  73. m_bReadOnly = FALSE;
  74. m_bMulti = pOldAttr->m_bMulti;
  75. m_bDirty = pOldAttr->m_bDirty;
  76. }
  77. CADSIAttr::~CADSIAttr()
  78. {
  79. _FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
  80. }
  81. ADSVALUE* CADSIAttr::GetADSVALUE(int idx)
  82. {
  83. return &(m_pAttrInfo->pADsValues[idx]);
  84. }
  85. HRESULT CADSIAttr::SetValues(const CStringList& sValues)
  86. {
  87. HRESULT hr = S_OK;
  88. ADS_ATTR_INFO* pNewAttrInfo = NULL;
  89. if (!_CopyADsAttrInfo(m_pAttrInfo, &pNewAttrInfo))
  90. {
  91. return E_FAIL;
  92. }
  93. int iCount = sValues.GetCount();
  94. pNewAttrInfo->dwNumValues = iCount;
  95. if (!_AllocValues(&pNewAttrInfo->pADsValues, iCount))
  96. {
  97. return E_FAIL;
  98. }
  99. int idx = 0;
  100. POSITION pos = sValues.GetHeadPosition();
  101. while (pos != NULL)
  102. {
  103. CString s = sValues.GetNext(pos);
  104. ADSVALUE* pADsValue = &(pNewAttrInfo->pADsValues[idx]);
  105. ASSERT(pADsValue != NULL);
  106. hr = _SetADsFromString(
  107. s,
  108. pNewAttrInfo->dwADsType,
  109. pADsValue
  110. );
  111. if (FAILED(hr))
  112. {
  113. _FreeADsAttrInfo(&pNewAttrInfo, FALSE);
  114. return hr;
  115. }
  116. idx++;
  117. }
  118. // Free the old one and swap in the new one
  119. //
  120. _FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
  121. m_pAttrInfo = pNewAttrInfo;
  122. m_bReadOnly = FALSE;
  123. return hr;
  124. }
  125. void CADSIAttr::GetValues(CStringList& sValues, DWORD dwMaxCharCount)
  126. {
  127. GetStringFromADs(m_pAttrInfo, sValues, dwMaxCharCount);
  128. }
  129. ADS_ATTR_INFO* CADSIAttr::GetAttrInfo()
  130. {
  131. return m_pAttrInfo;
  132. }
  133. ////////////////////////////////////////////////////////////////////////
  134. // Public Helper Functions
  135. ///////////////////////////////////////////////////////////////////////
  136. HRESULT CADSIAttr::SetValuesInDS(CAttrList* ptouchedAttr, IDirectoryObject* pDirObject)
  137. {
  138. DWORD dwReturn;
  139. DWORD dwAttrCount = 0;
  140. ADS_ATTR_INFO* pAttrInfo;
  141. pAttrInfo = new ADS_ATTR_INFO[ptouchedAttr->GetCount()];
  142. CADSIAttr* pCurrentAttr;
  143. POSITION pos = ptouchedAttr->GetHeadPosition();
  144. while(pos != NULL)
  145. {
  146. ptouchedAttr->GetNextDirty(pos, &pCurrentAttr);
  147. if (pCurrentAttr != NULL)
  148. {
  149. ADS_ATTR_INFO* pCurrentAttrInfo = pCurrentAttr->GetAttrInfo();
  150. ADS_ATTR_INFO* pNewAttrInfo = &pAttrInfo[dwAttrCount];
  151. if (!_CopyADsAttrInfo(pCurrentAttrInfo, pNewAttrInfo))
  152. {
  153. for (int itr = 0; itr < dwAttrCount; itr++)
  154. {
  155. _FreeADsAttrInfo(&pAttrInfo[itr]);
  156. }
  157. delete[] pAttrInfo;
  158. return E_FAIL;
  159. }
  160. if (!_CopyADsValues(pCurrentAttrInfo, pNewAttrInfo))
  161. {
  162. delete[] pAttrInfo;
  163. return E_FAIL;
  164. }
  165. if (pAttrInfo[dwAttrCount].dwNumValues == 0)
  166. {
  167. pAttrInfo[dwAttrCount].dwControlCode = ADS_ATTR_CLEAR;
  168. }
  169. else
  170. {
  171. pAttrInfo[dwAttrCount].dwControlCode = ADS_ATTR_UPDATE;
  172. }
  173. dwAttrCount++;
  174. }
  175. }
  176. // Commit the changes that have been made to the ADSI cache
  177. //
  178. HRESULT hr = pDirObject->SetObjectAttributes(pAttrInfo, dwAttrCount, &dwReturn);
  179. for (int itr = 0; itr < dwAttrCount; itr++)
  180. {
  181. _FreeADsAttrInfo(&pAttrInfo[itr]);
  182. }
  183. delete[] pAttrInfo;
  184. return hr;
  185. }
  186. /////////////////////////////////////////////////////////////////////////
  187. // Private Helper Functions
  188. ////////////////////////////////////////////////////////////////////////
  189. // NOTICE-2002/02/25-artm _SetADsFromString() w/in trust boundary
  190. // Pre: lpszValue != NULL && lpszValue is a zero terminated string
  191. HRESULT CADSIAttr::_SetADsFromString(LPCWSTR lpszValue, ADSTYPE adsType, ADSVALUE* pADsValue)
  192. {
  193. HRESULT hr = E_FAIL;
  194. if ( adsType == ADSTYPE_INVALID )
  195. {
  196. return hr;
  197. }
  198. pADsValue->dwType = adsType;
  199. switch( adsType )
  200. {
  201. case ADSTYPE_DN_STRING :
  202. if (!_AllocString(lpszValue, &pADsValue->DNString))
  203. {
  204. return E_FAIL;
  205. }
  206. hr = S_OK;
  207. break;
  208. case ADSTYPE_CASE_EXACT_STRING :
  209. if (!_AllocString(lpszValue, &pADsValue->CaseExactString))
  210. {
  211. return E_FAIL;
  212. }
  213. hr = S_OK;
  214. break;
  215. case ADSTYPE_CASE_IGNORE_STRING :
  216. if (!_AllocString(lpszValue, &pADsValue->CaseIgnoreString))
  217. {
  218. return E_FAIL;
  219. }
  220. hr = S_OK;
  221. break;
  222. case ADSTYPE_PRINTABLE_STRING :
  223. if (!_AllocString(lpszValue, &pADsValue->PrintableString))
  224. {
  225. return E_FAIL;
  226. }
  227. hr = S_OK;
  228. break;
  229. case ADSTYPE_NUMERIC_STRING :
  230. if (!_AllocString(lpszValue, &pADsValue->NumericString))
  231. {
  232. return E_FAIL;
  233. }
  234. hr = S_OK;
  235. break;
  236. case ADSTYPE_OBJECT_CLASS :
  237. if (!_AllocString(lpszValue, &pADsValue->ClassName))
  238. {
  239. return E_FAIL;
  240. }
  241. hr = S_OK;
  242. break;
  243. case ADSTYPE_BOOLEAN :
  244. // FUTURE-2002/02/22-artm Use constants for literal strings, and use
  245. // a function to determine their length. Easier to maintain, read, and
  246. // less error prone. If performance is a concern, calculate the lengths
  247. // once and assign to length constants.
  248. // NOTICE-2002/02/25-artm lpszValue must be null terminated
  249. // This requirement is currently met by the functions that call
  250. // this helper.
  251. if (_wcsnicmp(lpszValue, L"TRUE", 4) == 0)
  252. {
  253. (DWORD)pADsValue->Boolean = TRUE;
  254. }
  255. else if (_wcsnicmp(lpszValue, L"FALSE", 5) == 0)
  256. {
  257. (DWORD)pADsValue->Boolean = FALSE;
  258. }
  259. else
  260. {
  261. return E_FAIL;
  262. }
  263. hr = S_OK;
  264. break;
  265. case ADSTYPE_INTEGER :
  266. int value;
  267. // As long as lpszValue is a valid string (even empty string is okay),
  268. // swscanf will convert the number from a string to an int.
  269. value = swscanf(lpszValue, L"%ld", &pADsValue->Integer);
  270. if (value > 0)
  271. {
  272. hr = S_OK;
  273. }
  274. else
  275. {
  276. hr = E_FAIL;
  277. }
  278. break;
  279. case ADSTYPE_OCTET_STRING :
  280. {
  281. hr = HexStringToByteArray_0x(
  282. lpszValue,
  283. &( pADsValue->OctetString.lpValue ),
  284. pADsValue->OctetString.dwLength);
  285. // Should never happen.
  286. ASSERT (hr != E_POINTER);
  287. }
  288. break;
  289. case ADSTYPE_LARGE_INTEGER :
  290. wtoli(lpszValue, pADsValue->LargeInteger);
  291. hr = S_OK;
  292. break;
  293. case ADSTYPE_UTC_TIME :
  294. int iNum;
  295. WORD n;
  296. // NOTICE-2002/02/25-artm Validates that input string by
  297. // checking that all 6 time fields were filled in. Relies
  298. // on input string being null terminated (okay as long as
  299. // function contract met).
  300. iNum = swscanf(lpszValue, L"%02d/%02d/%04d %02d:%02d:%02d",
  301. &n,
  302. &pADsValue->UTCTime.wDay,
  303. &pADsValue->UTCTime.wYear,
  304. &pADsValue->UTCTime.wHour,
  305. &pADsValue->UTCTime.wMinute,
  306. &pADsValue->UTCTime.wSecond
  307. );
  308. pADsValue->UTCTime.wMonth = n;
  309. // This strange conversion is done so that the DayOfWeek will be set in
  310. // the UTCTime. By converting it to a filetime it ignores the dayofweek but
  311. // converting back fills it in.
  312. //
  313. FILETIME ft;
  314. SystemTimeToFileTime(&pADsValue->UTCTime, &ft);
  315. FileTimeToSystemTime(&ft, &pADsValue->UTCTime);
  316. if (iNum == 6)
  317. {
  318. hr = S_OK;
  319. }
  320. else
  321. {
  322. hr = E_FAIL;
  323. }
  324. break;
  325. default :
  326. break;
  327. }
  328. return hr;
  329. }
  330. // Copies the old octet string to the new octet string. Any memory allocated
  331. // to the new octet string will be freed first (and will be freed even if the
  332. // copy failed).
  333. BOOL CADSIAttr::_AllocOctetString(ADS_OCTET_STRING& rOldOctetString,
  334. ADS_OCTET_STRING& rNew)
  335. {
  336. _FreeOctetString(rNew.lpValue);
  337. int iLength = rOldOctetString.dwLength;
  338. rNew.dwLength = iLength;
  339. rNew.lpValue = new BYTE[iLength];
  340. if (rNew.lpValue == NULL)
  341. {
  342. // FUTURE-2002/02/25-artm Unnecessary function call.
  343. // Calling _FreeOctetString() does nothing here since
  344. // we can only get to this code branch if the allocation
  345. // failed.
  346. _FreeOctetString(rNew.lpValue);
  347. return FALSE;
  348. }
  349. memcpy(rNew.lpValue, rOldOctetString.lpValue, iLength);
  350. return TRUE;
  351. }
  352. void CADSIAttr::_FreeOctetString(BYTE* lpValue)
  353. {
  354. if (lpValue != NULL)
  355. {
  356. // NOTICE-NTRAID#NTBUG9-554582-2002/02/25-artm Memory leak b/c lpValue allocated with [].
  357. // Code should be delete [] lpValue.
  358. delete [] lpValue;
  359. lpValue = NULL;
  360. }
  361. }
  362. // NOTICE-2002/02/25-artm lpsz must be a null terminated string
  363. BOOL CADSIAttr::_AllocString(LPCWSTR lpsz, LPWSTR* lppszNew)
  364. {
  365. _FreeString(lppszNew);
  366. int iLength = wcslen(lpsz);
  367. *lppszNew = new WCHAR[iLength + 1]; // an extra for the NULL
  368. if (*lppszNew == NULL)
  369. {
  370. // FUTURE-2002/02/25-artm Unnecessary function call.
  371. // Calling _FreeString() does nothing here since
  372. // we can only get to this code branch if the allocation
  373. // failed.
  374. _FreeString(lppszNew);
  375. return FALSE;
  376. }
  377. // This is a legitimate use of wcscpy() since the destination buffer
  378. // is sized large enought to hold the src and terminating null. It
  379. // hinges on the fact that the source string is null terminated.
  380. wcscpy(*lppszNew, lpsz);
  381. return TRUE;
  382. }
  383. void CADSIAttr::_FreeString(LPWSTR* lppsz)
  384. {
  385. if (*lppsz != NULL)
  386. {
  387. // NOTICE-NTRAID#NTBUG9-554582-2002/02/25-artm Memory leak b/c lppsz allocated with [].
  388. // Code should be delete [] lppsz.
  389. delete [] *lppsz;
  390. }
  391. *lppsz = NULL;
  392. }
  393. BOOL CADSIAttr::_AllocValues(ADSVALUE** ppValues, DWORD dwLength)
  394. {
  395. _FreeADsValues(ppValues, dwLength);
  396. *ppValues = new ADSVALUE[dwLength];
  397. if (*ppValues == NULL)
  398. {
  399. // FUTURE-2002/02/25-artm Unnecessary function call.
  400. // Calling _FreeADsValues() does nothing here since
  401. // we can only get to this code branch if the allocation
  402. // failed.
  403. _FreeADsValues(ppValues, dwLength);
  404. return FALSE;
  405. }
  406. memset(*ppValues, 0, sizeof(ADSVALUE) * dwLength);
  407. return TRUE;
  408. }
  409. BOOL CADSIAttr::_CopyADsValues(ADS_ATTR_INFO* pOldAttrInfo, ADS_ATTR_INFO* pNewAttrInfo)
  410. {
  411. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  412. pNewAttrInfo->dwNumValues = pOldAttrInfo->dwNumValues;
  413. if (!_AllocValues(&pNewAttrInfo->pADsValues, pOldAttrInfo->dwNumValues))
  414. {
  415. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  416. return FALSE;
  417. }
  418. for (int itr = 0; itr < pOldAttrInfo->dwNumValues; itr++)
  419. {
  420. pNewAttrInfo->pADsValues[itr].dwType = pOldAttrInfo->pADsValues[itr].dwType;
  421. switch( pNewAttrInfo->pADsValues[itr].dwType )
  422. {
  423. case ADSTYPE_DN_STRING :
  424. if (!_AllocString(pOldAttrInfo->pADsValues[itr].DNString,
  425. &pNewAttrInfo->pADsValues[itr].DNString))
  426. {
  427. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  428. return FALSE;
  429. }
  430. break;
  431. case ADSTYPE_CASE_EXACT_STRING :
  432. if (!_AllocString(pOldAttrInfo->pADsValues[itr].CaseExactString,
  433. &pNewAttrInfo->pADsValues[itr].CaseExactString))
  434. {
  435. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  436. return FALSE;
  437. }
  438. break;
  439. case ADSTYPE_CASE_IGNORE_STRING :
  440. if (!_AllocString(pOldAttrInfo->pADsValues[itr].CaseIgnoreString,
  441. &pNewAttrInfo->pADsValues[itr].CaseIgnoreString))
  442. {
  443. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  444. return FALSE;
  445. }
  446. break;
  447. case ADSTYPE_PRINTABLE_STRING :
  448. if (!_AllocString(pOldAttrInfo->pADsValues[itr].PrintableString,
  449. &pNewAttrInfo->pADsValues[itr].PrintableString))
  450. {
  451. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  452. return FALSE;
  453. }
  454. break;
  455. case ADSTYPE_NUMERIC_STRING :
  456. if (!_AllocString(pOldAttrInfo->pADsValues[itr].NumericString,
  457. &pNewAttrInfo->pADsValues[itr].NumericString))
  458. {
  459. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  460. return FALSE;
  461. }
  462. break;
  463. case ADSTYPE_OBJECT_CLASS :
  464. if (!_AllocString(pOldAttrInfo->pADsValues[itr].ClassName,
  465. &pNewAttrInfo->pADsValues[itr].ClassName))
  466. {
  467. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  468. return FALSE;
  469. }
  470. break;
  471. case ADSTYPE_BOOLEAN :
  472. pNewAttrInfo->pADsValues[itr].Boolean = pOldAttrInfo->pADsValues[itr].Boolean;
  473. break;
  474. case ADSTYPE_INTEGER :
  475. pNewAttrInfo->pADsValues[itr].Integer = pOldAttrInfo->pADsValues[itr].Integer;
  476. break;
  477. case ADSTYPE_OCTET_STRING :
  478. if (!_AllocOctetString(pOldAttrInfo->pADsValues[itr].OctetString,
  479. pNewAttrInfo->pADsValues[itr].OctetString))
  480. {
  481. _FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
  482. return FALSE;
  483. }
  484. break;
  485. case ADSTYPE_LARGE_INTEGER :
  486. pNewAttrInfo->pADsValues[itr].LargeInteger = pOldAttrInfo->pADsValues[itr].LargeInteger;
  487. break;
  488. case ADSTYPE_UTC_TIME :
  489. pNewAttrInfo->pADsValues[itr].UTCTime = pOldAttrInfo->pADsValues[itr].UTCTime;
  490. break;
  491. default :
  492. break;
  493. }
  494. }
  495. return TRUE;
  496. }
  497. void CADSIAttr::_FreeADsValues(ADSVALUE** ppADsValues, DWORD dwLength)
  498. {
  499. ADSVALUE* pADsValue = *ppADsValues;
  500. for (int idx = 0; idx < dwLength; idx++)
  501. {
  502. if (pADsValue != NULL)
  503. {
  504. switch( pADsValue->dwType )
  505. {
  506. case ADSTYPE_DN_STRING :
  507. _FreeString(&pADsValue->DNString);
  508. break;
  509. case ADSTYPE_CASE_EXACT_STRING :
  510. _FreeString(&pADsValue->CaseExactString);
  511. break;
  512. case ADSTYPE_CASE_IGNORE_STRING :
  513. _FreeString(&pADsValue->CaseIgnoreString);
  514. break;
  515. case ADSTYPE_PRINTABLE_STRING :
  516. _FreeString(&pADsValue->PrintableString);
  517. break;
  518. case ADSTYPE_NUMERIC_STRING :
  519. _FreeString(&pADsValue->NumericString);
  520. break;
  521. case ADSTYPE_OBJECT_CLASS :
  522. _FreeString(&pADsValue->ClassName);
  523. break;
  524. case ADSTYPE_OCTET_STRING :
  525. _FreeOctetString(pADsValue->OctetString.lpValue);
  526. break;
  527. default :
  528. break;
  529. }
  530. pADsValue++;
  531. }
  532. }
  533. // May be NULL if there are no values set
  534. // WARNING! : make sure that you memset the memory after
  535. // creating an ADS_ATTR_INFO so that it will be NULL if there
  536. // are no values
  537. //
  538. if (*ppADsValues != NULL)
  539. {
  540. // NOTICE-NTRAID#NTBUG9-554582-2002/02/25-artm Memory leak b/c *ppADsValues allocated with [].
  541. // Code should be delete [] *ppADsValues.
  542. delete [] *ppADsValues;
  543. *ppADsValues = NULL;
  544. }
  545. }
  546. // The values are not copied here. They must be copied after the ADS_ATTR_INFO
  547. // is copied by using _CopyADsValues()
  548. //
  549. BOOL CADSIAttr::_CopyADsAttrInfo(ADS_ATTR_INFO* pAttrInfo, ADS_ATTR_INFO** ppNewAttrInfo)
  550. {
  551. _FreeADsAttrInfo(ppNewAttrInfo, FALSE);
  552. *ppNewAttrInfo = new ADS_ATTR_INFO;
  553. if (*ppNewAttrInfo == NULL)
  554. {
  555. return FALSE;
  556. }
  557. memset(*ppNewAttrInfo, 0, sizeof(ADS_ATTR_INFO));
  558. BOOL bReturn = _AllocString(pAttrInfo->pszAttrName, &((*ppNewAttrInfo)->pszAttrName));
  559. if (!bReturn)
  560. {
  561. _FreeADsAttrInfo(ppNewAttrInfo, FALSE);
  562. return FALSE;
  563. }
  564. (*ppNewAttrInfo)->dwADsType = pAttrInfo->dwADsType;
  565. (*ppNewAttrInfo)->dwControlCode = pAttrInfo->dwControlCode;
  566. (*ppNewAttrInfo)->dwNumValues = pAttrInfo->dwNumValues;
  567. return TRUE;
  568. }
  569. BOOL CADSIAttr::_CopyADsAttrInfo(ADS_ATTR_INFO* pAttrInfo, ADS_ATTR_INFO* pNewAttrInfo)
  570. {
  571. memset(pNewAttrInfo, 0, sizeof(ADS_ATTR_INFO));
  572. BOOL bReturn = _AllocString(pAttrInfo->pszAttrName, &pNewAttrInfo->pszAttrName);
  573. if (!bReturn)
  574. {
  575. return FALSE;
  576. }
  577. pNewAttrInfo->dwADsType = pAttrInfo->dwADsType;
  578. pNewAttrInfo->dwControlCode = pAttrInfo->dwControlCode;
  579. pNewAttrInfo->dwNumValues = pAttrInfo->dwNumValues;
  580. return TRUE;
  581. }
  582. void CADSIAttr::_FreeADsAttrInfo(ADS_ATTR_INFO** ppAttrInfo, BOOL bReadOnly)
  583. {
  584. if (*ppAttrInfo == NULL)
  585. {
  586. return;
  587. }
  588. if (!bReadOnly)
  589. {
  590. _FreeString(&(*ppAttrInfo)->pszAttrName);
  591. _FreeADsValues(&(*ppAttrInfo)->pADsValues, (*ppAttrInfo)->dwNumValues);
  592. delete *ppAttrInfo;
  593. }
  594. else
  595. {
  596. FreeADsMem(*ppAttrInfo);
  597. }
  598. *ppAttrInfo = NULL;
  599. }
  600. void CADSIAttr::_FreeADsAttrInfo(ADS_ATTR_INFO* pAttrInfo)
  601. {
  602. if (pAttrInfo == NULL)
  603. {
  604. return;
  605. }
  606. _FreeString(&pAttrInfo->pszAttrName);
  607. _FreeADsValues(&pAttrInfo->pADsValues, pAttrInfo->dwNumValues);
  608. }