windows-nt/Source/XPSP1/NT/com/ole32/cs/backend/dsprop.cxx
2020-09-26 16:20:57 +08:00

681 lines
20 KiB
C++

#include "cstore.hxx"
// 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)
{
CoTaskMemFree(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 *)CoTaskMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return; // BUGBUG:: return the hresult.
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 *)CoTaskMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return; // BUGBUG:: return the hresult.
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 *)CoTaskMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return; // BUGBUG:: return the hresult.
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 *)CoTaskMemAlloc(sizeof(ADSVALUE));
if (!(attr->pADsValues))
return; // BUGBUG:: return the hresult.
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)
{
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)))
wcscpy(szDescription, (ptr+CAT_DESC_DELIM_LEN+2));
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)))
wcscpy(szDescription, (ptr+CAT_DESC_DELIM_LEN+2));
else
szDescription = L'\0';
}
if (GetPrimary)
*plcid = newlcid;
return i+1;
}
}
return 0;
}
DWORD NumDigits10(DWORD Value)
{
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];
LPCTSTR Msg[2];
HANDLE hEventLogHandle;
Msg[0] = szContainerName;
Msg[1] = szErrCode;
wsprintf(szErrCode, L"0x%x", ExtendedErrorCode);
hEventLogHandle = RegisterEventSource(NULL, CLASSSTORE_EVENT_SOURCE);
if (!hEventLogHandle)
{
#if DBG
// Don't want to call call CSDBGPrint
WCHAR Msg[_MAX_PATH];
wsprintf(Msg, L"CSTORE: ReportEventCS: Couldn't open event log. Error returned 0x%x\n", GetLastError());
OutputDebugString(Msg);
#endif // DBG
return;
}
switch (ErrorCode) {
case CS_E_INVALID_VERSION:
ReportEvent(hEventLogHandle,
EVENTLOG_ERROR_TYPE,
0,
EVENT_CS_INVALID_VERSION,
NULL,
2,
0,
Msg,
NULL
);
break;
case CS_E_NETWORK_ERROR:
ReportEvent(hEventLogHandle,
EVENTLOG_ERROR_TYPE,
0,
EVENT_CS_NETWORK_ERROR,
NULL,
2,
0,
Msg,
NULL
);
break;
case CS_E_INVALID_PATH:
ReportEvent(hEventLogHandle,
EVENTLOG_ERROR_TYPE,
0,
EVENT_CS_INVALID_PATH,
NULL,
2,
0,
Msg,
NULL
);
break;
case CS_E_SCHEMA_MISMATCH:
ReportEvent(hEventLogHandle,
EVENTLOG_ERROR_TYPE,
0,
EVENT_CS_SCHEMA_MISMATCH,
NULL,
2,
0,
Msg,
NULL
);
break;
case CS_E_INTERNAL_ERROR:
ReportEvent(hEventLogHandle,
EVENTLOG_ERROR_TYPE,
0,
EVENT_CS_INTERNAL_ERROR,
NULL,
2,
0,
Msg,
NULL
);
break;
}
BOOL bDeregistered;
bDeregistered = DeregisterEventSource(hEventLogHandle);
if (!bDeregistered)
{
#if DBG
// Don't want to call call CSDBGPrint
WCHAR Msg[_MAX_PATH];
wsprintf(Msg, L"CSTORE: ReportEventCS: Couldn't Deregister event log. Error returned 0x%x\n", GetLastError());
OutputDebugString(Msg);
#endif // DBG
}
}
// remapping Error Codes returned by LDAP to reasonable class store errors.
//
HRESULT RemapErrorCode(HRESULT ErrorCode, LPOLESTR m_szContainerName)
{
HRESULT RetCode;
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 Denails
//
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;
//
// Any DNS, DS or Network failures
//
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 = CS_E_NETWORK_ERROR;
break;
case HRESULT_FROM_WIN32(ERROR_DS_ADMIN_LIMIT_EXCEEDED):
RetCode = CS_E_ADMIN_LIMIT_EXCEEDED;
break;
case CS_E_OBJECT_NOTFOUND:
case CS_E_OBJECT_ALREADY_EXISTS:
case CS_E_INVALID_VERSION:
case CS_E_PACKAGE_NOTFOUND:
RetCode = ErrorCode;
break;
case E_INVALIDARG:
case ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS:
RetCode = E_INVALIDARG;
break;
default:
RetCode = CS_E_INTERNAL_ERROR;
}
CSDBGPrint((L"Error Code 0x%x remapped to 0x%x\n", ErrorCode, RetCode));
if ((RetCode == CS_E_INVALID_PATH) ||
(RetCode == CS_E_NETWORK_ERROR) ||
(RetCode == CS_E_INVALID_VERSION) ||
(RetCode == CS_E_SCHEMA_MISMATCH) ||
(RetCode == CS_E_INTERNAL_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 *)CoTaskMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return; // BUGBUG:: return the hresult.
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 *)CoTaskMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return; // BUGBUG:: return the hresult.
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 *)CoTaskMemAlloc(sizeof(ADSVALUE)*num);
if (!(attr->pADsValues))
return; // BUGBUG:: return the hresult.
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 LogMessage(WCHAR *wszDebugBuffer)
{
HANDLE hFile = NULL;
hFile = CreateFile(LOGFILE,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if ( hFile != INVALID_HANDLE_VALUE )
{
if ( SetFilePointer (hFile, 0, NULL, FILE_END) != 0xFFFFFFFF )
{
char * pszString;
DWORD Size;
int Status;
Size = lstrlen(wszDebugBuffer) + 1;
pszString = (char *) CoTaskMemAlloc( Size );
if ( pszString )
{
Status = WideCharToMultiByte(
CP_ACP,
0,
wszDebugBuffer,
-1,
pszString,
Size,
NULL,
NULL );
if ( Status )
{
WriteFile(
hFile,
(LPCVOID) pszString,
lstrlenA(pszString) * sizeof(char),
&Size,
NULL );
}
}
CoTaskMemFree(pszString);
}
CloseHandle (hFile);
}
}
void CSDbgPrint(WCHAR *Format, ...)
{
WCHAR wszDebugTitle[50], wszMsg[500];
SYSTEMTIME systime;
WCHAR wszDebugBuffer[500];
DWORD dwErrCode = 0;
va_list VAList;
LPCTSTR Msg[1];
if ((gDebugLog) || (gDebugOut))
{
dwErrCode = GetLastError();
va_start(VAList, Format);
GetLocalTime( &systime );
wsprintf( wszDebugTitle, L"CSTORE (%x) %02d:%02d:%02d:%03d ",
GetCurrentProcessId(),
systime.wHour, systime.wMinute, systime.wSecond,
systime.wMilliseconds);
wvsprintf(wszMsg, Format, VAList);
wsprintf(wszDebugBuffer, L"%s:: %s\n", wszDebugTitle, wszMsg);
if (gDebugOut)
OutputDebugString(wszDebugBuffer);
if (gDebugLog)
LogMessage(wszDebugBuffer);
if (gDebugEventLog)
{
HANDLE hEventLogHandle;
// we don't need time etc. for event log.
// it should be added
hEventLogHandle = RegisterEventSource(NULL, CLASSSTORE_EVENT_SOURCE);
if (!hEventLogHandle)
{
#if DBG
// Don't want to call call CSDBGPrint
WCHAR Msg[_MAX_PATH];
wsprintf(Msg, L"CSTORE: CSDbgPrint: Couldn't open event log. Error returned 0x%x\n", GetLastError());
OutputDebugString(Msg);
#endif // DBG
}
if (hEventLogHandle)
{
Msg[0] = wszMsg;
ReportEvent(hEventLogHandle,
EVENTLOG_INFORMATION_TYPE,
0,
EVENT_CS_CLASSSTORE_DEBUGMSG,
NULL,
1,
0,
Msg,
NULL
);
BOOL bDeregistered;
bDeregistered = DeregisterEventSource(hEventLogHandle);
if (!bDeregistered)
{
#if DBG
// Don't want to call call CSDBGPrint
WCHAR Msg[_MAX_PATH];
wsprintf(Msg, L"CSTORE: CSDbgPrint: Couldn't Deregister event log. Error returned 0x%x\n", GetLastError());
OutputDebugString(Msg);
#endif // DBG
}
}
}
SetLastError(dwErrCode);
}
}