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.
 
 
 
 
 
 

716 lines
20 KiB

#include "cstore.hxx"
const WCHAR cwszCRLF[] = L"\r\n";
BOOL GetGpoIdFromClassStorePath(
WCHAR* wszClassStorePath,
GUID* pGpoId)
{
WCHAR* wszGuidStart;
WCHAR wszGpoId[MAX_GUIDSTR_LEN + 1];
wszGuidStart = wcschr(wszClassStorePath, L'{');
if (!wszGuidStart)
{
return FALSE;
}
wcsncpy(wszGpoId, wszGuidStart, MAX_GUIDSTR_LEN);
wszGpoId[MAX_GUIDSTR_LEN] = L'\0';
StringToGuid(wszGpoId, pGpoId);
return TRUE;
}
HRESULT GetUserSid(PSID *ppUserSid, UINT *pCallType);
// set property routines do not do any allocations.
// get properties have 2 different sets of routines
// 1. in which there is no allocation taking place
// and the buffers are freed when the ds data structures
// are freed.
// 2. Allocation takes place and these should be used for
// data that needs to be returned back to the clients.
void FreeAttr(ADS_ATTR_INFO attr)
{
CsMemFree(attr.pADsValues);
}
// Note: None of these APIs copies anything into their own buffers.
// It allocates a buffer for adsvalues though.
// packing a property's value into a attribute structure
// for sending in with a create/modify.
void PackStrArrToAttr(ADS_ATTR_INFO *attr, WCHAR *szProperty,
WCHAR **pszAttr, DWORD num)
{
DWORD i;
attr->pszAttrName = szProperty;
attr->dwNumValues = num;
if (num)
attr->dwControlCode = ADS_ATTR_UPDATE;
else
attr->dwControlCode = ADS_ATTR_CLEAR;
attr->dwADsType = ADSTYPE_DN_STRING;
attr->pADsValues = (ADSVALUE *)CsMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return;
for (i = 0; i < num; i++) {
attr->pADsValues[i].dwType = ADSTYPE_DN_STRING;
attr->pADsValues[i].DNString = pszAttr[i];
}
}
void PackDWArrToAttr(ADS_ATTR_INFO *attr, WCHAR *szProperty, DWORD *pAttr, DWORD num)
{
DWORD i;
attr->pszAttrName = szProperty;
attr->dwNumValues = num;
if (num)
attr->dwControlCode = ADS_ATTR_UPDATE;
else
attr->dwControlCode = ADS_ATTR_CLEAR;
attr->dwADsType = ADSTYPE_INTEGER;
attr->pADsValues = (ADSVALUE *)CsMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return;
for (i = 0; i < num; i++) {
attr->pADsValues[i].dwType = ADSTYPE_INTEGER;
attr->pADsValues[i].Integer = pAttr[i];
}
}
void PackGUIDArrToAttr(ADS_ATTR_INFO *attr, WCHAR *szProperty, GUID *pAttr, DWORD num)
{
DWORD i;
attr->pszAttrName = szProperty;
attr->dwNumValues = num;
if (num)
attr->dwControlCode = ADS_ATTR_UPDATE;
else
attr->dwControlCode = ADS_ATTR_CLEAR;
attr->dwADsType = ADSTYPE_OCTET_STRING;
attr->pADsValues = (ADSVALUE *)CsMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return;
for (i = 0; i < num; i++) {
attr->pADsValues[i].dwType = ADSTYPE_OCTET_STRING;
attr->pADsValues[i].OctetString.dwLength = sizeof(GUID);
attr->pADsValues[i].OctetString.lpValue = (unsigned char *)(pAttr+i);
}
}
void PackBinToAttr(ADS_ATTR_INFO *attr, WCHAR *szProperty, BYTE *pAttr, DWORD sz)
{
attr->pszAttrName = szProperty;
attr->dwNumValues = 1;
attr->dwControlCode = ADS_ATTR_UPDATE;
attr->dwADsType = ADSTYPE_OCTET_STRING;
attr->pADsValues = (ADSVALUE *)CsMemAlloc(sizeof(ADSVALUE));
if (!(attr->pADsValues))
return;
attr->pADsValues[0].dwType = ADSTYPE_OCTET_STRING;
attr->pADsValues[0].OctetString.dwLength = sz;
attr->pADsValues[0].OctetString.lpValue = pAttr;
}
void PackStrToAttr(ADS_ATTR_INFO *attr, WCHAR *szProperty, WCHAR *szAttr)
{
if (szAttr)
PackStrArrToAttr(attr, szProperty, &szAttr, 1);
else
PackStrArrToAttr(attr, szProperty, &szAttr, 0);
}
void PackDWToAttr(ADS_ATTR_INFO *attr, WCHAR *szProperty, DWORD Attr)
{
PackDWArrToAttr(attr, szProperty, &Attr, 1);
}
// passing in a pointer to GUID which is passed down into the LDAP structure.
void PackGUIDToAttr(ADS_ATTR_INFO *attr, WCHAR *szProperty, GUID *pAttr)
{
PackGUIDArrToAttr(attr, szProperty, pAttr, 1);
}
// returns the attribute corresp. to a given property.
DWORD GetPropertyFromAttr(ADS_ATTR_INFO *pattr, DWORD cNum, WCHAR *szProperty)
{
DWORD i;
for (i = 0; i < cNum; i++)
if (_wcsicmp(pattr[i].pszAttrName, szProperty) == 0)
break;
return i;
}
HRESULT GetCategoryLocaleDesc(LPOLESTR *pdesc, ULONG cdesc, LCID *plcid,
LPOLESTR szDescription, ULONG ulSize)
{
LCID plgid;
LPOLESTR ptr;
szDescription[0] = L'\0';
if (!cdesc)
return E_FAIL; // CAT_E_NODESCRIPTION;
// Try locale passed in
if (FindDescription(pdesc, cdesc, plcid, szDescription, 0))
return S_OK;
// Get default sublang local
plgid = PRIMARYLANGID((WORD)*plcid);
*plcid = MAKELCID(MAKELANGID(plgid, SUBLANG_DEFAULT), SORT_DEFAULT);
if (FindDescription(pdesc, cdesc, plcid, szDescription, 0))
return S_OK;
// Get matching lang id
if (FindDescription(pdesc, cdesc, plcid, szDescription, 1))
return S_OK;
// Get User Default
*plcid = GetUserDefaultLCID();
if (FindDescription(pdesc, cdesc, plcid, szDescription, 0))
return S_OK;
// Get System Default
*plcid = GetUserDefaultLCID();
if (FindDescription(pdesc, cdesc, plcid, szDescription, 0))
return S_OK;
// Get the first one
*plcid = wcstoul(pdesc[0], &ptr, 16);
if (szDescription)
{
if ((ptr) && (wcslen(ptr) >= (CAT_DESC_DELIM_LEN+2)))
{
HRESULT hr;
hr = StringCchCopy(szDescription, ulSize, (ptr+CAT_DESC_DELIM_LEN+2));
if (FAILED(hr))
{
return hr;
}
}
else
szDescription = L'\0';
}
return S_OK;
}
//-------------------------------------------
// Returns the description corresp. to a LCID
// desc: list of descs+lcid
// cdesc: number of elements.
// plcid: the lcid in/out
// szDescription:description returned.
// GetPrimary: Match only the primary.
//---------------------------------------
ULONG FindDescription(LPOLESTR *desc, ULONG cdesc, LCID *plcid, LPOLESTR szDescription, BOOL GetPrimary)
{
ULONG i;
LCID newlcid;
LPOLESTR ptr;
for (i = 0; i < cdesc; i++)
{
newlcid = wcstoul(desc[i], &ptr, 16); // to be changed
// error to be checked.
if ((newlcid == *plcid) || ((GetPrimary) &&
(PRIMARYLANGID((WORD)*plcid) == PRIMARYLANGID(LANGIDFROMLCID(newlcid)))))
{
if (szDescription)
{
if ((ptr) && (wcslen(ptr) >= (CAT_DESC_DELIM_LEN+2)))
{
//
// Copy the description, enforcing the maximum size
// so we don't overflow the buffer
//
wcsncpy(szDescription,
(ptr+CAT_DESC_DELIM_LEN+2),
CAT_DESC_MAX_LEN + 1
);
//
// We must null terminate in case the category
// was longer than the maximum. We know the buffer
// is equal in size to the maximum, so we can
// just add the terminator there. In all other cases,
// wcsncpy will have written the null terminator
//
szDescription[CAT_DESC_MAX_LEN] = L'\0';
}
else
szDescription = L'\0';
}
if (GetPrimary)
*plcid = newlcid;
return i+1;
}
}
return 0;
}
DWORD NumDigits10(DWORD Value)
{
if (0 == Value) {
return 1;
}
DWORD ret = 0;
for (ret = 0; Value != 0; ret++)
Value = Value/10;
return ret;
}
void ReportEventCS(HRESULT ErrorCode, HRESULT ExtendedErrorCode, LPOLESTR szContainerName)
{
WCHAR szErrCode[16];
HRESULT hr;
hr = StringCchPrintf(szErrCode, 16, L"0x%x", ExtendedErrorCode);
ASSERT(SUCCEEDED(hr));
CEventsBase* pEvents = (CEventsBase*) gpEvents;
ASSERT(CS_E_NETWORK_ERROR == ErrorCode);
pEvents->Report(
EVENT_CS_NETWORK_ERROR,
FALSE,
2,
szContainerName,
szErrCode);
}
// remapping Error Codes returned by LDAP to reasonable class store errors.
//
HRESULT RemapErrorCode(HRESULT ErrorCode, LPOLESTR m_szContainerName)
{
HRESULT RetCode;
BOOL fNetError;
fNetError = FALSE;
if (SUCCEEDED(ErrorCode))
return S_OK;
switch (ErrorCode)
{
//
// All kinds of failures due to ObjectNotFound
// due to non-existence of object OR
// non-existent container OR
// invalid path specification
// Other than Access Denials
//
case HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT):
case HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED): // understand what causes this
case HRESULT_FROM_WIN32(ERROR_DS_NAME_ERROR_NOT_FOUND): // -do-
RetCode = CS_E_OBJECT_NOTFOUND; // which object - specific error
break;
case HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS):
case HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS):
case E_ADS_OBJECT_EXISTS:
RetCode = CS_E_OBJECT_ALREADY_EXISTS;
break;
//
// The following errors should not be expected normally.
// Class Store schema mismatched should be handled correctly.
// Errors below may ONLY occur for corrupted data OR out-of-band changes
// to a Class Store content.
case E_ADS_CANT_CONVERT_DATATYPE:
case E_ADS_SCHEMA_VIOLATION:
case HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE):
case HRESULT_FROM_WIN32(ERROR_DS_CONSTRAINT_VIOLATION):
RetCode = CS_E_SCHEMA_MISMATCH;
break;
//
// Any kinds of Access or Auth Denial
// return ACCESS_DENIED
//
case HRESULT_FROM_WIN32(ERROR_DS_AUTH_METHOD_NOT_SUPPORTED):
case HRESULT_FROM_WIN32(ERROR_DS_STRONG_AUTH_REQUIRED):
case HRESULT_FROM_WIN32(ERROR_DS_CONFIDENTIALITY_REQUIRED):
case HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD):
case HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED):
case HRESULT_FROM_WIN32(ERROR_DS_AUTH_UNKNOWN):
RetCode = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
break;
case E_ADS_BAD_PATHNAME:
case HRESULT_FROM_WIN32(ERROR_DS_INVALID_ATTRIBUTE_SYNTAX): // this is wrong
RetCode = CS_E_INVALID_PATH;
break;
//
// Out of Memory
//
case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY):
case HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY):
RetCode = E_OUTOFMEMORY;
break;
case HRESULT_FROM_WIN32(ERROR_DS_NAME_ERROR_RESOLVING):
case HRESULT_FROM_WIN32(ERROR_DS_NAME_ERROR_NOT_UNIQUE):
case HRESULT_FROM_WIN32(ERROR_DS_NAME_ERROR_NO_MAPPING):
case HRESULT_FROM_WIN32(ERROR_DS_NAME_ERROR_DOMAIN_ONLY):
case HRESULT_FROM_WIN32(ERROR_DS_TIMELIMIT_EXCEEDED):
case HRESULT_FROM_WIN32(ERROR_DS_BUSY):
case HRESULT_FROM_WIN32(ERROR_DS_UNAVAILABLE):
case HRESULT_FROM_WIN32(ERROR_DS_UNWILLING_TO_PERFORM):
case HRESULT_FROM_WIN32(ERROR_TIMEOUT):
case HRESULT_FROM_WIN32(ERROR_CONNECTION_REFUSED):
case HRESULT_FROM_WIN32(ERROR_DS_SERVER_DOWN):
case HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN):
RetCode = ErrorCode;
fNetError = TRUE;
break;
case HRESULT_FROM_WIN32(ERROR_DS_ADMIN_LIMIT_EXCEEDED):
RetCode = CS_E_ADMIN_LIMIT_EXCEEDED;
break;
default:
RetCode = ErrorCode;
}
CSDBGPrint((DM_WARNING,
IDS_CSTORE_REMAP_ERR,
ErrorCode,
RetCode));
if (RetCode == CS_E_NETWORK_ERROR)
{
ReportEventCS(RetCode, ErrorCode, m_szContainerName);
}
return RetCode;
}
// These functions are used to delete a single value from a
// multivalued property or append to a multivalued property
void PackStrArrToAttrEx(ADS_ATTR_INFO *attr, WCHAR *szProperty, WCHAR **pszAttr, DWORD num,
BOOL APPEND)
{
DWORD i;
attr->pszAttrName = szProperty;
attr->dwNumValues = num;
if (APPEND)
attr->dwControlCode = ADS_ATTR_APPEND;
else
attr->dwControlCode = ADS_ATTR_DELETE;
attr->dwADsType = ADSTYPE_DN_STRING;
attr->pADsValues = (ADSVALUE *)CsMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return;
for (i = 0; i < num; i++) {
attr->pADsValues[i].dwType = ADSTYPE_DN_STRING;
attr->pADsValues[i].DNString = pszAttr[i];
}
}
void PackDWArrToAttrEx(ADS_ATTR_INFO *attr, WCHAR *szProperty, DWORD *pAttr, DWORD num,
BOOL APPEND)
{
DWORD i;
attr->pszAttrName = szProperty;
attr->dwNumValues = num;
if (APPEND)
attr->dwControlCode = ADS_ATTR_APPEND;
else
attr->dwControlCode = ADS_ATTR_DELETE;
attr->dwADsType = ADSTYPE_INTEGER;
attr->pADsValues = (ADSVALUE *)CsMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return;
for (i = 0; i < num; i++) {
attr->pADsValues[i].dwType = ADSTYPE_INTEGER;
attr->pADsValues[i].Integer = pAttr[i];
}
}
void PackGUIDArrToAttrEx(ADS_ATTR_INFO *attr, WCHAR *szProperty, GUID *pAttr, DWORD num,
BOOL APPEND)
{
DWORD i;
attr->pszAttrName = szProperty;
attr->dwNumValues = num;
if (APPEND)
attr->dwControlCode = ADS_ATTR_APPEND;
else
attr->dwControlCode = ADS_ATTR_DELETE;
attr->dwADsType = ADSTYPE_OCTET_STRING;
attr->pADsValues = (ADSVALUE *)CsMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return;
for (i = 0; i < num; i++) {
attr->pADsValues[i].dwType = ADSTYPE_OCTET_STRING;
attr->pADsValues[i].OctetString.dwLength = sizeof(GUID);
attr->pADsValues[i].OctetString.lpValue = (unsigned char *)(pAttr+i);
}
}
WCHAR* AllocGpoPathFromClassStorePath( WCHAR* pszClassStorePath )
{
//
// The class store path looks like CN=ClassStore,CN=[Machine | User],<gpopath>
// So we will simply look for two "," starting at the beginning of the path.
// In doing this, we will take care not to access violate due to an incorrect path,
// Since there is the possiblity that an administrator could find the persisted
// class store path and mangle it, giving us an incorrect path that would
// not parse according to the structure above.
//
WCHAR* wszGpoPath;
//
// Check for the first ','
//
wszGpoPath = wcschr(pszClassStorePath, L',');
//
// If we get NULL here, that means there is no ',' and the path is corrupt
//
if ( ! wszGpoPath )
{
return NULL;
}
//
// Now check for the second ','
//
wszGpoPath = wcschr(wszGpoPath + 1, L',');
//
// Again, if we don't find the second ',',
// The path is corrupt
//
if ( ! wszGpoPath )
{
return NULL;
}
//
// Now move one past
//
wszGpoPath++;
//
// The caller desires their own copy, so we will allocate space for it
//
WCHAR* wszGpoPathResult;
ULONG ulNoBytes;
ulNoBytes = (wcslen( wszGpoPath ) + 1) * sizeof( *wszGpoPathResult );
wszGpoPathResult = (WCHAR*) CsMemAlloc(ulNoBytes);
if ( ! wszGpoPathResult )
{
return NULL;
}
//
// Now copy the gpo path
//
HRESULT hr;
hr = StringCbCopy( wszGpoPathResult, ulNoBytes, wszGpoPath );
if (FAILED(hr))
{
CsMemFree(wszGpoPathResult);
wszGpoPathResult = NULL;
}
return wszGpoPathResult;
}
HRESULT
GetEscapedNameFilter( WCHAR* wszName, WCHAR** ppwszEscapedName )
{
DWORD cbLen;
WCHAR* wszCurrent;
HRESULT hr;
ULONG ulCurSizeLeft;
//
// This function escapes package names so that they can be used in
// an ldap search filter. Names containing certain characters must
// be escaped since those characters are contained in the vocabulary
// for the search filter grammar.
//
//
// The set of characters that must be escaped and the appropriate
// escape sequences are described in RFC 2254
//
//
// Determine the maximum size needed for the filter. We include for 3
// times the length of the name since that is the upper bound on the
// length of the escaped name
//
//
// "(PackageAttr=\0" + "<*ppwszEscapedName>" + ")"
//
cbLen = sizeof( L"(" PACKAGENAME L"=" ) + ( lstrlen( wszName ) + 1 ) * sizeof( *wszName ) * 3;
*ppwszEscapedName = (WCHAR*) CsMemAlloc( cbLen );
if ( ! *ppwszEscapedName )
{
return E_OUTOFMEMORY;
}
//
// Add in the LHS of the filter expression
//
hr = StringCbCopy( *ppwszEscapedName, cbLen, L"(" PACKAGENAME L"=" );
if (FAILED(hr))
{
CsMemFree(*ppwszEscapedName);
*ppwszEscapedName = NULL;
return hr;
}
//
// We will escape the name -- move past the end of the filter expression LHS
//
wszCurrent = *ppwszEscapedName + ( sizeof(L"(" PACKAGENAME L"=") - 1 ) / sizeof( WCHAR );
ulCurSizeLeft = (cbLen - (sizeof(L"(" PACKAGENAME L"=") - 1)) / sizeof(WCHAR);
//
// For each character that needs to be escaped, we will append that character's
// escape sequence to the string. For characters that do not need to be escaped,
// we simply simply append the character as-is (i.e. unescaped).
//
for ( ; *wszName; wszName++ )
{
WCHAR* EscapedChar;
//
// Detect characters that need to be escaped and
// map each to its escape sequence
//
switch ( *wszName )
{
case L'*':
EscapedChar = L"\\2a";
break;
case L'(':
EscapedChar = L"\\28";
break;
case L')':
EscapedChar = L"\\29";
break;
case L'\\':
EscapedChar = L"\\5c";
break;
default:
//
// This character does not need to be escaped, just append it
//
*wszCurrent = *wszName;
wszCurrent ++;
ulCurSizeLeft--;
continue;
break;
}
//
// We only get here if the character needed to be escaped --
// we append the string for the escape sequence to the filter string, and
// move our filter string location to the new end of string
//
hr = StringCchCopy( wszCurrent, ulCurSizeLeft, EscapedChar );
wszCurrent += 3;
ulCurSizeLeft-=3;
}
//
// We need to add the closing parenthesis to the filter expression
//
*wszCurrent++ = L')';
*wszCurrent = L'\0';
return S_OK;
}