|
|
#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; }
|