windows-nt/Source/XPSP1/NT/admin/snapin/adsiedit/attr.cpp
2020-09-26 16:20:57 +08:00

807 lines
17 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: attribute.cpp
//
//--------------------------------------------------------------------------
#include "pch.h"
#include "common.h"
#include "attr.h"
///////////////////////////////////////////////////////////////////////////
// CADSIAttribute
CADSIAttribute::CADSIAttribute(ADS_ATTR_INFO* pInfo, BOOL bMulti, PCWSTR pszSyntax, BOOL bReadOnly)
{
m_pAttrInfo = pInfo;
m_bDirty = FALSE;
m_bMulti = bMulti;
m_bReadOnly = bReadOnly;
m_bSet = FALSE;
m_bMandatory = FALSE;
m_szSyntax = pszSyntax;
PWSTR pwz = wcsrchr(pInfo->pszAttrName, L';');
if (pwz)
{
pwz; // move past the hyphen to the range end value.
ASSERT(*pwz);
*pwz=L'\0';
}
}
CADSIAttribute::CADSIAttribute(PADS_ATTR_INFO pInfo)
{
//
// REVIEW_JEFFJON : these need to be updated with correct values
//
m_pAttrInfo = pInfo;
m_bDirty = FALSE;
m_bMulti = FALSE;
m_bReadOnly = FALSE;
m_bSet = FALSE;
m_bMandatory = FALSE;
PWSTR pwz = wcsrchr(pInfo->pszAttrName, L';');
if (pwz)
{
pwz; // move past the hyphen to the range end value.
ASSERT(*pwz);
*pwz=L'\0';
}
}
CADSIAttribute::CADSIAttribute(LPCWSTR lpszAttr)
{
m_pAttrInfo = new ADS_ATTR_INFO;
memset(m_pAttrInfo, 0, sizeof(ADS_ATTR_INFO));
PWSTR pwz = wcsrchr(lpszAttr, L';');
if (pwz)
{
pwz; // move past the hyphen to the range end value.
ASSERT(*pwz);
*pwz=L'\0';
}
_AllocString(lpszAttr, &(m_pAttrInfo->pszAttrName));
m_bMulti = FALSE;
m_bDirty = FALSE;
m_bReadOnly = FALSE;
m_bSet = FALSE;
m_bMandatory = FALSE;
}
CADSIAttribute::CADSIAttribute(CADSIAttribute* pOldAttr)
{
m_pAttrInfo = NULL;
ADS_ATTR_INFO* pAttrInfo = pOldAttr->GetAttrInfo();
// These copies are done separately because there are places
// that I need to copy only the ADsAttrInfo and not the values
//
_CopyADsAttrInfo(pAttrInfo, &m_pAttrInfo);
_CopyADsValues(pAttrInfo, m_pAttrInfo );
m_bReadOnly = FALSE;
m_bMulti = pOldAttr->m_bMulti;
m_bDirty = pOldAttr->m_bDirty;
m_szSyntax = pOldAttr->m_szSyntax;
}
CADSIAttribute::~CADSIAttribute()
{
if (!m_bReadOnly)
{
_FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
}
}
ADSVALUE* CADSIAttribute::GetADSVALUE(int idx)
{
return &(m_pAttrInfo->pADsValues[idx]);
}
HRESULT CADSIAttribute::SetValues(PADSVALUE pADsValue, DWORD dwNumValues)
{
HRESULT hr = S_OK;
ADS_ATTR_INFO* pNewAttrInfo = NULL;
if (!_CopyADsAttrInfo(m_pAttrInfo, &pNewAttrInfo))
{
return E_FAIL;
}
pNewAttrInfo->dwNumValues = dwNumValues;
pNewAttrInfo->pADsValues = pADsValue;
if (pADsValue == NULL)
{
pNewAttrInfo->dwControlCode = ADS_ATTR_CLEAR;
}
else
{
pNewAttrInfo->dwADsType = pADsValue->dwType;
}
//
// Free the old one and swap in the new one
//
if (!m_bReadOnly)
{
_FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
}
m_pAttrInfo = pNewAttrInfo;
m_bReadOnly = FALSE;
return hr;
}
HRESULT CADSIAttribute::SetValues(const CStringList& sValues)
{
HRESULT hr;
ADS_ATTR_INFO* pNewAttrInfo = NULL;
if (!_CopyADsAttrInfo(m_pAttrInfo, &pNewAttrInfo))
{
return E_FAIL;
}
int iCount = sValues.GetCount();
pNewAttrInfo->dwNumValues = iCount;
if (!_AllocValues(&pNewAttrInfo->pADsValues, iCount))
{
return E_FAIL;
}
int idx = 0;
POSITION pos = sValues.GetHeadPosition();
while (pos != NULL)
{
CString s = sValues.GetNext(pos);
ADSVALUE* pADsValue = &(pNewAttrInfo->pADsValues[idx]);
ASSERT(pADsValue != NULL);
hr = _SetADsFromString(
s,
pNewAttrInfo->dwADsType,
pADsValue
);
if (FAILED(hr))
{
_FreeADsAttrInfo(&pNewAttrInfo, FALSE);
return hr;
}
idx++;
}
// Free the old one and swap in the new one
//
_FreeADsAttrInfo(&m_pAttrInfo, m_bReadOnly);
m_pAttrInfo = pNewAttrInfo;
m_bReadOnly = FALSE;
return hr;
}
void CADSIAttribute::GetValues(CStringList& sValues, DWORD dwMaxCharCount)
{
GetStringFromADs(m_pAttrInfo, sValues, dwMaxCharCount);
}
ADS_ATTR_INFO* CADSIAttribute::GetAttrInfo()
{
return m_pAttrInfo;
}
////////////////////////////////////////////////////////////////////////
// Public Helper Functions
///////////////////////////////////////////////////////////////////////
HRESULT CADSIAttribute::SetValuesInDS(CAttrList2* ptouchedAttr, IDirectoryObject* pDirObject)
{
DWORD dwReturn;
DWORD dwAttrCount = 0;
ADS_ATTR_INFO* pAttrInfo;
pAttrInfo = new ADS_ATTR_INFO[ptouchedAttr->GetCount()];
CADSIAttribute* pCurrentAttr;
POSITION pos = ptouchedAttr->GetHeadPosition();
while(pos != NULL)
{
ptouchedAttr->GetNextDirty(pos, &pCurrentAttr);
if (pCurrentAttr != NULL)
{
ADS_ATTR_INFO* pCurrentAttrInfo = pCurrentAttr->GetAttrInfo();
ADS_ATTR_INFO* pNewAttrInfo = &pAttrInfo[dwAttrCount];
if (!_CopyADsAttrInfo(pCurrentAttrInfo, pNewAttrInfo))
{
for (DWORD itr = 0; itr < dwAttrCount; itr++)
{
_FreeADsAttrInfo(&pAttrInfo[itr]);
}
delete[] pAttrInfo;
pAttrInfo = NULL;
return E_FAIL;
}
if (!_CopyADsValues(pCurrentAttrInfo, pNewAttrInfo))
{
delete[] pAttrInfo;
pAttrInfo = NULL;
return E_FAIL;
}
if (pAttrInfo[dwAttrCount].dwNumValues == 0)
{
pAttrInfo[dwAttrCount].dwControlCode = ADS_ATTR_CLEAR;
}
else
{
pAttrInfo[dwAttrCount].dwControlCode = ADS_ATTR_UPDATE;
}
dwAttrCount++;
}
}
// Commit the changes that have been made to the ADSI cache
//
HRESULT hr = pDirObject->SetObjectAttributes(pAttrInfo, dwAttrCount, &dwReturn);
for (DWORD itr = 0; itr < dwAttrCount; itr++)
{
_FreeADsAttrInfo(&pAttrInfo[itr]);
}
delete[] pAttrInfo;
pAttrInfo = NULL;
return hr;
}
/////////////////////////////////////////////////////////////////////////
// Private Helper Functions
////////////////////////////////////////////////////////////////////////
HRESULT CADSIAttribute::_SetADsFromString(LPCWSTR lpszValue, ADSTYPE adsType, ADSVALUE* pADsValue)
{
HRESULT hr = E_FAIL;
if ( adsType == ADSTYPE_INVALID )
{
return hr;
}
pADsValue->dwType = adsType;
switch( adsType )
{
case ADSTYPE_DN_STRING :
if (!_AllocString(lpszValue, &pADsValue->DNString))
{
return E_FAIL;
}
hr = S_OK;
break;
case ADSTYPE_CASE_EXACT_STRING :
if (!_AllocString(lpszValue, &pADsValue->CaseExactString))
{
return E_FAIL;
}
hr = S_OK;
break;
case ADSTYPE_CASE_IGNORE_STRING :
if (!_AllocString(lpszValue, &pADsValue->CaseIgnoreString))
{
return E_FAIL;
}
hr = S_OK;
break;
case ADSTYPE_PRINTABLE_STRING :
if (!_AllocString(lpszValue, &pADsValue->PrintableString))
{
return E_FAIL;
}
hr = S_OK;
break;
case ADSTYPE_NUMERIC_STRING :
if (!_AllocString(lpszValue, &pADsValue->NumericString))
{
return E_FAIL;
}
hr = S_OK;
break;
case ADSTYPE_OBJECT_CLASS :
if (!_AllocString(lpszValue, &pADsValue->ClassName))
{
return E_FAIL;
}
hr = S_OK;
break;
case ADSTYPE_BOOLEAN :
if (_wcsnicmp(lpszValue, L"TRUE", 4) == 0)
{
(DWORD)pADsValue->Boolean = TRUE;
}
else if (_wcsnicmp(lpszValue, L"FALSE", 5) == 0)
{
(DWORD)pADsValue->Boolean = FALSE;
}
else
{
return E_FAIL;
}
hr = S_OK;
break;
case ADSTYPE_INTEGER :
int value;
value = swscanf(lpszValue, L"%ld", &pADsValue->Integer);
if (value > 0)
{
hr = S_OK;
}
else
{
hr = E_FAIL;
}
break;
case ADSTYPE_OCTET_STRING :
{
pADsValue->OctetString.lpValue = new BYTE[256];
int iCount = 0, index = 0, iResult = 0;
do
{
while (lpszValue[index] == ' ' || lpszValue[index] == '/t')
{
index++;
}
iResult = swscanf(&lpszValue[index], L"0x%2x", &pADsValue->OctetString.lpValue[iCount++]);
if (iResult == 0 && lpszValue[index] == '\0')
{
hr = S_OK;
break;
}
index += 4; // REVIEW : OctetStrings must be in the form 0x00, ie 4 characters
} while (iResult != 0);
iCount--; // the last one had to fail
pADsValue->OctetString.dwLength = iCount;
}
break;
case ADSTYPE_LARGE_INTEGER :
wtoli(lpszValue, pADsValue->LargeInteger);
hr = S_OK;
break;
case ADSTYPE_UTC_TIME :
int iNum;
WORD n;
iNum = swscanf(lpszValue, L"%02d/%02d/%04d %02d:%02d:%02d",
&n,
&pADsValue->UTCTime.wDay,
&pADsValue->UTCTime.wYear,
&pADsValue->UTCTime.wHour,
&pADsValue->UTCTime.wMinute,
&pADsValue->UTCTime.wSecond
);
pADsValue->UTCTime.wMonth = n;
// This strange conversion is done so that the DayOfWeek will be set in
// the UTCTime. By converting it to a filetime it ignores the dayofweek but
// converting back fills it in.
//
FILETIME ft;
SystemTimeToFileTime(&pADsValue->UTCTime, &ft);
FileTimeToSystemTime(&ft, &pADsValue->UTCTime);
if (iNum == 6)
{
hr = S_OK;
}
else
{
hr = E_FAIL;
}
break;
default :
break;
}
return hr;
}
BOOL CADSIAttribute::_AllocOctetString(ADS_OCTET_STRING& rOldOctetString,
ADS_OCTET_STRING& rNew)
{
_FreeOctetString(rNew.lpValue);
int iLength = rOldOctetString.dwLength;
rNew.dwLength = iLength;
rNew.lpValue = new BYTE[iLength];
if (rNew.lpValue == NULL)
{
_FreeOctetString(rNew.lpValue);
return FALSE;
}
memcpy(rNew.lpValue, rOldOctetString.lpValue, iLength);
return TRUE;
}
void CADSIAttribute::_FreeOctetString(BYTE* lpValue)
{
if (lpValue != NULL)
{
delete lpValue;
lpValue = NULL;
}
}
BOOL CADSIAttribute::_AllocString(LPCWSTR lpsz, LPWSTR* lppszNew)
{
_FreeString(lppszNew);
int iLength = wcslen(lpsz);
*lppszNew = new WCHAR[iLength + 1]; // an extra for the NULL
if (*lppszNew == NULL)
{
_FreeString(lppszNew);
return FALSE;
}
wcscpy(*lppszNew, lpsz);
return TRUE;
}
void CADSIAttribute::_FreeString(LPWSTR* lppsz)
{
if (*lppsz != NULL)
{
delete *lppsz;
}
*lppsz = NULL;
}
BOOL CADSIAttribute::_AllocValues(ADSVALUE** ppValues, DWORD dwLength)
{
_FreeADsValues(ppValues, dwLength);
*ppValues = new ADSVALUE[dwLength];
if (*ppValues == NULL)
{
_FreeADsValues(ppValues, dwLength);
return FALSE;
}
memset(*ppValues, 0, sizeof(ADSVALUE) * dwLength);
return TRUE;
}
BOOL CADSIAttribute::_CopyADsValues(ADS_ATTR_INFO* pOldAttrInfo, ADS_ATTR_INFO* pNewAttrInfo)
{
_FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
pNewAttrInfo->dwNumValues = pOldAttrInfo->dwNumValues;
if (!_AllocValues(&pNewAttrInfo->pADsValues, pOldAttrInfo->dwNumValues))
{
_FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
return FALSE;
}
for (DWORD itr = 0; itr < pOldAttrInfo->dwNumValues; itr++)
{
pNewAttrInfo->pADsValues[itr].dwType = pOldAttrInfo->pADsValues[itr].dwType;
switch( pNewAttrInfo->pADsValues[itr].dwType )
{
case ADSTYPE_DN_STRING :
if (!_AllocString(pOldAttrInfo->pADsValues[itr].DNString,
&pNewAttrInfo->pADsValues[itr].DNString))
{
_FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
return FALSE;
}
break;
case ADSTYPE_CASE_EXACT_STRING :
if (!_AllocString(pOldAttrInfo->pADsValues[itr].CaseExactString,
&pNewAttrInfo->pADsValues[itr].CaseExactString))
{
_FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
return FALSE;
}
break;
case ADSTYPE_CASE_IGNORE_STRING :
if (!_AllocString(pOldAttrInfo->pADsValues[itr].CaseIgnoreString,
&pNewAttrInfo->pADsValues[itr].CaseIgnoreString))
{
_FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
return FALSE;
}
break;
case ADSTYPE_PRINTABLE_STRING :
if (!_AllocString(pOldAttrInfo->pADsValues[itr].PrintableString,
&pNewAttrInfo->pADsValues[itr].PrintableString))
{
_FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
return FALSE;
}
break;
case ADSTYPE_NUMERIC_STRING :
if (!_AllocString(pOldAttrInfo->pADsValues[itr].NumericString,
&pNewAttrInfo->pADsValues[itr].NumericString))
{
_FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
return FALSE;
}
break;
case ADSTYPE_OBJECT_CLASS :
if (!_AllocString(pOldAttrInfo->pADsValues[itr].ClassName,
&pNewAttrInfo->pADsValues[itr].ClassName))
{
_FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
return FALSE;
}
break;
case ADSTYPE_BOOLEAN :
pNewAttrInfo->pADsValues[itr].Boolean = pOldAttrInfo->pADsValues[itr].Boolean;
break;
case ADSTYPE_INTEGER :
pNewAttrInfo->pADsValues[itr].Integer = pOldAttrInfo->pADsValues[itr].Integer;
break;
case ADSTYPE_OCTET_STRING :
if (!_AllocOctetString(pOldAttrInfo->pADsValues[itr].OctetString,
pNewAttrInfo->pADsValues[itr].OctetString))
{
_FreeADsValues(&pNewAttrInfo->pADsValues, pNewAttrInfo->dwNumValues);
return FALSE;
}
break;
case ADSTYPE_LARGE_INTEGER :
pNewAttrInfo->pADsValues[itr].LargeInteger = pOldAttrInfo->pADsValues[itr].LargeInteger;
break;
case ADSTYPE_UTC_TIME :
pNewAttrInfo->pADsValues[itr].UTCTime = pOldAttrInfo->pADsValues[itr].UTCTime;
break;
default :
break;
}
}
return TRUE;
}
void CADSIAttribute::_FreeADsValues(ADSVALUE** ppADsValues, DWORD dwLength)
{
ADSVALUE* pADsValue = *ppADsValues;
for (DWORD idx = 0; idx < dwLength; idx++)
{
if (pADsValue != NULL)
{
switch( pADsValue->dwType )
{
case ADSTYPE_DN_STRING :
_FreeString(&pADsValue->DNString);
break;
case ADSTYPE_CASE_EXACT_STRING :
_FreeString(&pADsValue->CaseExactString);
break;
case ADSTYPE_CASE_IGNORE_STRING :
_FreeString(&pADsValue->CaseIgnoreString);
break;
case ADSTYPE_PRINTABLE_STRING :
_FreeString(&pADsValue->PrintableString);
break;
case ADSTYPE_NUMERIC_STRING :
_FreeString(&pADsValue->NumericString);
break;
case ADSTYPE_OBJECT_CLASS :
_FreeString(&pADsValue->ClassName);
break;
case ADSTYPE_OCTET_STRING :
_FreeOctetString(pADsValue->OctetString.lpValue);
break;
default :
break;
}
pADsValue++;
}
}
// May be NULL if there are no values set
// WARNING! : make sure that you memset the memory after
// creating an ADS_ATTR_INFO so that it will be NULL if there
// are no values
//
if (*ppADsValues != NULL)
{
delete *ppADsValues;
*ppADsValues = NULL;
}
}
// The values are not copied here. They must be copied after the ADS_ATTR_INFO
// is copied by using _CopyADsValues()
//
BOOL CADSIAttribute::_CopyADsAttrInfo(ADS_ATTR_INFO* pAttrInfo, ADS_ATTR_INFO** ppNewAttrInfo)
{
_FreeADsAttrInfo(ppNewAttrInfo, FALSE);
*ppNewAttrInfo = new ADS_ATTR_INFO;
if (*ppNewAttrInfo == NULL)
{
return FALSE;
}
memset(*ppNewAttrInfo, 0, sizeof(ADS_ATTR_INFO));
BOOL bReturn = _AllocString(pAttrInfo->pszAttrName, &((*ppNewAttrInfo)->pszAttrName));
if (!bReturn)
{
_FreeADsAttrInfo(ppNewAttrInfo, FALSE);
return FALSE;
}
(*ppNewAttrInfo)->dwADsType = pAttrInfo->dwADsType;
(*ppNewAttrInfo)->dwControlCode = pAttrInfo->dwControlCode;
(*ppNewAttrInfo)->dwNumValues = pAttrInfo->dwNumValues;
return TRUE;
}
BOOL CADSIAttribute::_CopyADsAttrInfo(ADS_ATTR_INFO* pAttrInfo, ADS_ATTR_INFO* pNewAttrInfo)
{
memset(pNewAttrInfo, 0, sizeof(ADS_ATTR_INFO));
BOOL bReturn = _AllocString(pAttrInfo->pszAttrName, &pNewAttrInfo->pszAttrName);
if (!bReturn)
{
return FALSE;
}
pNewAttrInfo->dwADsType = pAttrInfo->dwADsType;
pNewAttrInfo->dwControlCode = pAttrInfo->dwControlCode;
pNewAttrInfo->dwNumValues = pAttrInfo->dwNumValues;
return TRUE;
}
void CADSIAttribute::_FreeADsAttrInfo(ADS_ATTR_INFO** ppAttrInfo, BOOL bReadOnly)
{
if (*ppAttrInfo == NULL)
{
return;
}
if (!bReadOnly)
{
_FreeString(&(*ppAttrInfo)->pszAttrName);
_FreeADsValues(&(*ppAttrInfo)->pADsValues, (*ppAttrInfo)->dwNumValues);
delete *ppAttrInfo;
}
else
{
FreeADsMem(*ppAttrInfo);
}
*ppAttrInfo = NULL;
}
void CADSIAttribute::_FreeADsAttrInfo(ADS_ATTR_INFO* pAttrInfo)
{
if (pAttrInfo == NULL)
{
return;
}
_FreeString(&pAttrInfo->pszAttrName);
_FreeADsValues(&pAttrInfo->pADsValues, pAttrInfo->dwNumValues);
}
///////////////////////////////////////////////////////////////////////////
// CAttrList2
POSITION CAttrList2::FindProperty(LPCWSTR lpszAttr)
{
CADSIAttribute* pAttr;
for (POSITION p = GetHeadPosition(); p != NULL; GetNext(p))
{
// I use GetAt here because I don't want to advance the POSITION
// because it is returned if they are equal
//
pAttr = GetAt(p);
CString sName;
pAttr->GetProperty(sName);
if (wcscmp(sName, lpszAttr) == 0)
{
break;
}
}
return p;
}
BOOL CAttrList2::HasProperty(LPCWSTR lpszAttr)
{
POSITION pos = FindProperty(lpszAttr);
return pos != NULL;
}
// Searches through the cache for the attribute
// ppAttr will point to the CADSIAttribute if found, NULL if not
//
void CAttrList2::GetNextDirty(POSITION& pos, CADSIAttribute** ppAttr)
{
*ppAttr = GetNext(pos);
if (pos == NULL && !(*ppAttr)->IsDirty())
{
*ppAttr = NULL;
return;
}
while (!(*ppAttr)->IsDirty() && pos != NULL)
{
*ppAttr = GetNext(pos);
if (!(*ppAttr)->IsDirty() && pos == NULL)
{
*ppAttr = NULL;
break;
}
}
}
BOOL CAttrList2::HasDirty()
{
POSITION pos = GetHeadPosition();
while (pos != NULL)
{
CADSIAttribute* pAttr = GetNext(pos);
if (pAttr->IsDirty())
{
return TRUE;
}
}
return FALSE;
}