From 337124bed6a57b40fca11c5c2f5b554f570522a6 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Tue, 4 May 2021 11:41:55 -0700 Subject: Move ComPlus.wixext into ext --- src/ext/ComPlus/ca/cputilexec.cpp | 1881 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1881 insertions(+) create mode 100644 src/ext/ComPlus/ca/cputilexec.cpp (limited to 'src/ext/ComPlus/ca/cputilexec.cpp') diff --git a/src/ext/ComPlus/ca/cputilexec.cpp b/src/ext/ComPlus/ca/cputilexec.cpp new file mode 100644 index 00000000..1c2c8b93 --- /dev/null +++ b/src/ext/ComPlus/ca/cputilexec.cpp @@ -0,0 +1,1881 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// private structs + +struct CPI_WELLKNOWN_SID +{ + LPCWSTR pwzName; + SID_IDENTIFIER_AUTHORITY iaIdentifierAuthority; + BYTE nSubAuthorityCount; + DWORD dwSubAuthority[8]; +}; + + +// well known SIDs + +CPI_WELLKNOWN_SID wsWellKnownSids[] = { + {L"\\Everyone", SECURITY_WORLD_SID_AUTHORITY, 1, {SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\Administrators", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0}}, + {L"\\LocalSystem", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\LocalService", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\NetworkService", SECURITY_NT_AUTHORITY, 1, {SECURITY_NETWORK_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\AuthenticatedUser", SECURITY_NT_AUTHORITY, 1, {SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0}}, + {L"\\Guests", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0, 0, 0, 0, 0, 0}}, + {L"\\Users", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0}}, + {L"\\CREATOR OWNER", SECURITY_NT_AUTHORITY, 1, {SECURITY_CREATOR_OWNER_RID, 0, 0, 0, 0, 0, 0, 0}}, + {NULL, SECURITY_NULL_SID_AUTHORITY, 0, {0, 0, 0, 0, 0, 0, 0, 0}} +}; + + +// prototypes for private helper functions + +static HRESULT FindUserCollectionObjectIndex( + ICatalogCollection* piColl, + PSID pSid, + int* pi + ); +static HRESULT CreateSidFromDomainRidPair( + PSID pDomainSid, + DWORD dwRid, + PSID* ppSid + ); +static HRESULT InitLsaUnicodeString( + PLSA_UNICODE_STRING plusStr, + LPCWSTR pwzStr, + DWORD dwLen + ); +static void FreeLsaUnicodeString( + PLSA_UNICODE_STRING plusStr + ); +static HRESULT WriteFileAll( + HANDLE hFile, + PBYTE pbBuffer, + DWORD dwBufferLength + ); +static HRESULT ReadFileAll( + HANDLE hFile, + PBYTE pbBuffer, + DWORD dwBufferLength + ); + + +// variables + +static ICOMAdminCatalog* gpiCatalog; + + +// function definitions + +void CpiExecInitialize() +{ + // collections + gpiCatalog = NULL; +} + +void CpiExecFinalize() +{ + // collections + ReleaseObject(gpiCatalog); +} + +HRESULT CpiActionStartMessage( + LPWSTR* ppwzActionData, + BOOL fSuppress + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hRec; + + LPWSTR pwzData = NULL; + + // create record + hRec = ::MsiCreateRecord(3); + ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record"); + + // action name + hr = WcaReadStringFromCaData(ppwzActionData, &pwzData); + ExitOnFailure(hr, "Failed to action name"); + + er = ::MsiRecordSetStringW(hRec, 1, pwzData); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set action name"); + + // description + hr = WcaReadStringFromCaData(ppwzActionData, &pwzData); + ExitOnFailure(hr, "Failed to description"); + + er = ::MsiRecordSetStringW(hRec, 2, pwzData); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set description"); + + // template + hr = WcaReadStringFromCaData(ppwzActionData, &pwzData); + ExitOnFailure(hr, "Failed to template"); + + er = ::MsiRecordSetStringW(hRec, 3, pwzData); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set template"); + + // message + if (!fSuppress) + { + er = WcaProcessMessage(INSTALLMESSAGE_ACTIONSTART, hRec); + if (0 == er || IDOK == er || IDYES == er) + { + hr = S_OK; + } + else if (IDABORT == er || IDCANCEL == er) + { + WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit + hr = S_FALSE; + } + else + hr = E_UNEXPECTED; + } + +LExit: + // clean up + ReleaseStr(pwzData); + + return hr; +} + +HRESULT CpiActionDataMessage( + DWORD cArgs, + ... + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + PMSIHANDLE hRec; + va_list args; + + // record + hRec = ::MsiCreateRecord(cArgs); + ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record"); + + va_start(args, cArgs); + for (DWORD i = 1; i <= cArgs; i++) + { + LPCWSTR pwzArg = va_arg(args, WCHAR*); + if (pwzArg && *pwzArg) + { + er = ::MsiRecordSetStringW(hRec, i, pwzArg); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set record field string"); + } + } + va_end(args); + + // message + er = WcaProcessMessage(INSTALLMESSAGE_ACTIONDATA, hRec); + if (0 == er || IDOK == er || IDYES == er) + { + hr = S_OK; + } + else if (IDABORT == er || IDCANCEL == er) + { + WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit + hr = S_FALSE; + } + else + hr = E_UNEXPECTED; + +LExit: + return hr; +} + +HRESULT CpiExecGetAdminCatalog( + ICOMAdminCatalog** ppiCatalog + ) +{ + HRESULT hr = S_OK; + + if (!gpiCatalog) + { + // get collection + hr = ::CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_ALL, IID_ICOMAdminCatalog, (void**)&gpiCatalog); + ExitOnFailure(hr, "Failed to create COM+ admin catalog object"); + } + + // return value + gpiCatalog->AddRef(); + *ppiCatalog = gpiCatalog; + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiLogCatalogErrorInfo() +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + ICatalogCollection* piErrColl = NULL; + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + LPWSTR pwzName = NULL; + LPWSTR pwzErrorCode = NULL; + LPWSTR pwzMajorRef = NULL; + LPWSTR pwzMinorRef = NULL; + + // get catalog + hr = CpiExecGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get error info collection + hr = CpiExecGetCatalogCollection(L"ErrorInfo", &piErrColl); + ExitOnFailure(hr, "Failed to get error info collection"); + + // loop objects + long lCnt; + hr = piErrColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piErrColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get item from partitions collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // get properties + hr = CpiGetCollectionObjectValue(piObj, L"Name", &pwzName); + ExitOnFailure(hr, "Failed to get name"); + hr = CpiGetCollectionObjectValue(piObj, L"ErrorCode", &pwzErrorCode); + ExitOnFailure(hr, "Failed to get error code"); + hr = CpiGetCollectionObjectValue(piObj, L"MajorRef", &pwzMajorRef); + ExitOnFailure(hr, "Failed to get major ref"); + hr = CpiGetCollectionObjectValue(piObj, L"MinorRef", &pwzMinorRef); + ExitOnFailure(hr, "Failed to get minor ref"); + + // write to log + WcaLog(LOGMSG_STANDARD, "ErrorInfo: Name='%S', ErrorCode='%S', MajorRef='%S', MinorRef='%S'", + pwzName, pwzErrorCode, pwzMajorRef, pwzMinorRef); + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piErrColl); + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ReleaseStr(pwzName); + ReleaseStr(pwzErrorCode); + ReleaseStr(pwzMajorRef); + ReleaseStr(pwzMinorRef); + + return hr; +} + +HRESULT CpiExecGetCatalogCollection( + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + IDispatch* piDisp = NULL; + + BSTR bstrName = NULL; + + // copy name string + bstrName = ::SysAllocString(pwzName); + ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); + + // get catalog + hr = CpiExecGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get collecton from catalog + hr = piCatalog->GetCollection(bstrName, &piDisp); + ExitOnFailure(hr, "Failed to get collection"); + + hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl); + ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface"); + + // populate collection + hr = (*ppiColl)->Populate(); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to populate collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piDisp); + ReleaseBSTR(bstrName); + + return hr; +} + +HRESULT CpiExecGetCatalogCollection( + ICatalogCollection* piColl, + ICatalogObject* piObj, + LPCWSTR pwzName, + ICatalogCollection** ppiColl + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + IDispatch* piDisp = NULL; + + BSTR bstrName = NULL; + + VARIANT vtKey; + ::VariantInit(&vtKey); + + // copy name string + bstrName = ::SysAllocString(pwzName); + ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for collection name"); + + // get catalog + hr = CpiExecGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get key + hr = piObj->get_Key(&vtKey); + ExitOnFailure(hr, "Failed to get object key"); + + // get collecton from catalog + hr = piColl->GetCollection(bstrName, vtKey, &piDisp); + ExitOnFailure(hr, "Failed to get collection"); + + hr = piDisp->QueryInterface(IID_ICatalogCollection, (void**)ppiColl); + ExitOnFailure(hr, "Failed to get IID_ICatalogCollection interface"); + + // populate collection + hr = (*ppiColl)->Populate(); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to populate collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piDisp); + ReleaseBSTR(bstrName); + ::VariantClear(&vtKey); + + return hr; +} + +HRESULT CpiAddCollectionObject( + ICatalogCollection* piColl, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + + hr = piColl->Add(&piDisp); + ExitOnFailure(hr, "Failed to add object to collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)ppiObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piDisp); + + return hr; +} + +HRESULT CpiPutCollectionObjectValue( + ICatalogObject* piObj, + LPCWSTR pwzPropName, + LPCWSTR pwzValue + ) +{ + HRESULT hr = S_OK; + + BSTR bstrPropName = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + // allocate property name string + bstrPropName = ::SysAllocString(pwzPropName); + ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate property name string"); + + // prepare value variant + vtVal.vt = VT_BSTR; + vtVal.bstrVal = ::SysAllocString(pwzValue); + ExitOnNull(vtVal.bstrVal, hr, E_OUTOFMEMORY, "Failed to allocate property value string"); + + // put value + hr = piObj->put_Value(bstrPropName, vtVal); + ExitOnFailure(hr, "Failed to put property value"); + + hr = S_OK; + +LExit: + // clean up + ReleaseBSTR(bstrPropName); + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiPutCollectionObjectValues( + ICatalogObject* piObj, + CPI_PROPERTY* pPropList + ) +{ + HRESULT hr = S_OK; + + for (CPI_PROPERTY* pItm = pPropList; pItm; pItm = pItm->pNext) + { + // set property + hr = CpiPutCollectionObjectValue(piObj, pItm->wzName, pItm->pwzValue); + ExitOnFailure(hr, "Failed to set object property value, name: %S", pItm->wzName); + } + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetCollectionObjectValue( + ICatalogObject* piObj, + LPCWSTR szPropName, + LPWSTR* ppwzValue + ) +{ + HRESULT hr = S_OK; + + BSTR bstrPropName = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + // allocate property name string + bstrPropName = ::SysAllocString(szPropName); + ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate property name string"); + + // get value + hr = piObj->get_Value(bstrPropName, &vtVal); + ExitOnFailure(hr, "Failed to get property value"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + hr = StrAllocString(ppwzValue, vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal)); + ExitOnFailure(hr, "Failed to allocate memory for value string"); + + hr = S_OK; + +LExit: + // clean up + ReleaseBSTR(bstrPropName); + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiResetObjectProperty( + ICatalogCollection* piColl, + ICatalogObject* piObj, + LPCWSTR pwzPropName + ) +{ + HRESULT hr = S_OK; + + BSTR bstrPropName = NULL; + + long lChanges = 0; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + // allocate property name string + bstrPropName = ::SysAllocString(pwzPropName); + ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "Failed to allocate deleteable property name string"); + + // get value + hr = piObj->get_Value(bstrPropName, &vtVal); + ExitOnFailure(hr, "Failed to get deleteable property value"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BOOL); + ExitOnFailure(hr, "Failed to change variant type"); + + // if the deleteable property is set + if (VARIANT_FALSE == vtVal.boolVal) + { + // clear property + vtVal.boolVal = VARIANT_TRUE; + + hr = piObj->put_Value(bstrPropName, vtVal); + ExitOnFailure(hr, "Failed to get property value"); + + // save changes + hr = piColl->SaveChanges(&lChanges); + if (COMADMIN_E_OBJECTERRORS == hr) + CpiLogCatalogErrorInfo(); + ExitOnFailure(hr, "Failed to save changes"); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseBSTR(bstrPropName); + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiRemoveCollectionObject( + ICatalogCollection* piColl, + LPCWSTR pwzID, + LPCWSTR pwzName, + BOOL fResetDeleteable + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + BOOL fMatch = FALSE; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + long lCnt; + hr = piColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // compare id + if (pwzID && *pwzID) + { + hr = piObj->get_Key(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpiW(vtVal.bstrVal, pwzID)) + fMatch = TRUE; + + ::VariantClear(&vtVal); + } + + // compare name + if (pwzName && *pwzName) + { + hr = piObj->get_Name(&vtVal); + ExitOnFailure(hr, "Failed to get name"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpW(vtVal.bstrVal, pwzName)) + fMatch = TRUE; + + ::VariantClear(&vtVal); + } + + // if it's a match, remove it + if (fMatch) + { + if (fResetDeleteable) + { + // reset deleteable property, if set + hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable"); + ExitOnFailure(hr, "Failed to reset deleteable property"); + } + + hr = piColl->Remove(i); + ExitOnFailure(hr, "Failed to remove item from collection"); + break; + } + + // release interface pointers + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiRemoveUserCollectionObject( + ICatalogCollection* piColl, + PSID pSid + ) +{ + HRESULT hr = S_OK; + + int i = 0; + + // find index + hr = FindUserCollectionObjectIndex(piColl, pSid, &i); + ExitOnFailure(hr, "Failed to find user collection index"); + + if (S_FALSE == hr) + ExitFunction(); // not found, exit with hr = S_FALSE + + // remove object + hr = piColl->Remove(i); + ExitOnFailure(hr, "Failed to remove object from collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiFindCollectionObjectByStringKey( + ICatalogCollection* piColl, + LPCWSTR pwzKey, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + long lCnt; + hr = piColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // compare key + hr = piObj->get_Key(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpiW(vtVal.bstrVal, pwzKey)) + { + if (ppiObj) + { + *ppiObj = piObj; + piObj = NULL; + } + ExitFunction1(hr = S_OK); + } + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + + ::VariantClear(&vtVal); + } + + hr = S_FALSE; + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiFindCollectionObjectByIntegerKey( + ICatalogCollection* piColl, + long lKey, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + long lCnt; + hr = piColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // compare key + hr = piObj->get_Key(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_I4); + ExitOnFailure(hr, "Failed to change variant type"); + + if (vtVal.lVal == lKey) + { + if (ppiObj) + { + *ppiObj = piObj; + piObj = NULL; + } + ExitFunction1(hr = S_OK); + } + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + + ::VariantClear(&vtVal); + } + + hr = S_FALSE; + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiFindCollectionObjectByName( + ICatalogCollection* piColl, + LPCWSTR pwzName, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + + VARIANT vtVal; + ::VariantInit(&vtVal); + + long lCnt; + hr = piColl->get_Count(&lCnt); + ExitOnFailure(hr, "Failed to get to number of items in collection"); + + for (long i = 0; i < lCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // compare key + hr = piObj->get_Name(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + if (0 == lstrcmpW(vtVal.bstrVal, pwzName)) + { + if (ppiObj) + { + *ppiObj = piObj; + piObj = NULL; + } + ExitFunction1(hr = S_OK); + } + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + + ::VariantClear(&vtVal); + } + + hr = S_FALSE; + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + + ::VariantClear(&vtVal); + + return hr; +} + +HRESULT CpiFindUserCollectionObject( + ICatalogCollection* piColl, + PSID pSid, + ICatalogObject** ppiObj + ) +{ + HRESULT hr = S_OK; + + int i = 0; + + IDispatch* piDisp = NULL; + + // find index + hr = FindUserCollectionObjectIndex(piColl, pSid, &i); + ExitOnFailure(hr, "Failed to find user collection index"); + + if (S_FALSE == hr) + ExitFunction(); // not found, exit with hr = S_FALSE + + // get object + if (ppiObj) + { + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)ppiObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piDisp); + + return hr; +} + +HRESULT CpiExecGetPartitionsCollection( + ICatalogCollection** ppiPartColl + ) +{ + HRESULT hr = S_OK; + + // get collection + hr = CpiExecGetCatalogCollection(L"Partitions", ppiPartColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetPartitionRolesCollection( + LPCWSTR pwzPartID, + ICatalogCollection** ppiRolesColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + + // get partitions collection + hr = CpiExecGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + + if (S_FALSE == hr) + ExitFunction(); // partitions collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByStringKey(piPartColl, pwzPartID, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // partition not found, exit with hr = S_FALSE + + // get roles collection + hr = CpiExecGetCatalogCollection(piPartColl, piPartObj, L"RolesForPartition", ppiRolesColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + + return hr; +} + +HRESULT CpiGetUsersInPartitionRoleCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzRoleName, + ICatalogCollection** ppiUsrInRoleColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piRoleColl = NULL; + ICatalogObject* piRoleObj = NULL; + + // get roles collection + hr = CpiGetPartitionRolesCollection(pwzPartID, &piRoleColl); + ExitOnFailure(hr, "Failed to get roles collection"); + + if (S_FALSE == hr) + ExitFunction(); // partition roles collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByName(piRoleColl, pwzRoleName, &piRoleObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // user not found, exit with hr = S_FALSE + + // get roles collection + hr = CpiExecGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInPartitionRole", ppiUsrInRoleColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRoleColl); + ReleaseObject(piRoleObj); + + return hr; +} + +HRESULT CpiGetPartitionUsersCollection( + ICatalogCollection** ppiUserColl + ) +{ + HRESULT hr = S_OK; + + // get roles collection + hr = CpiExecGetCatalogCollection(L"PartitionUsers", ppiUserColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiExecGetApplicationsCollection( + LPCWSTR pwzPartID, + ICatalogCollection** ppiAppColl + ) +{ + HRESULT hr = S_OK; + + ICOMAdminCatalog* piCatalog = NULL; + ICOMAdminCatalog2* piCatalog2 = NULL; + BSTR bstrGlobPartID = NULL; + + ICatalogCollection* piPartColl = NULL; + ICatalogObject* piPartObj = NULL; + + // get catalog + hr = CpiExecGetAdminCatalog(&piCatalog); + ExitOnFailure(hr, "Failed to get COM+ admin catalog"); + + // get ICOMAdminCatalog2 interface + hr = piCatalog->QueryInterface(IID_ICOMAdminCatalog2, (void**)&piCatalog2); + + // COM+ 1.5 or later + if (E_NOINTERFACE != hr) + { + ExitOnFailure(hr, "Failed to get IID_ICOMAdminCatalog2 interface"); + + // partition id + if (!pwzPartID || !*pwzPartID) + { + // get global partition id + hr = piCatalog2->get_GlobalPartitionID(&bstrGlobPartID); + ExitOnFailure(hr, "Failed to get global partition id"); + } + + // get partitions collection + hr = CpiExecGetPartitionsCollection(&piPartColl); + ExitOnFailure(hr, "Failed to get partitions collection"); + + // find object + hr = CpiFindCollectionObjectByStringKey(piPartColl, bstrGlobPartID ? bstrGlobPartID : pwzPartID, &piPartObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // partition not found, exit with hr = S_FALSE + + // get applications collection + hr = CpiExecGetCatalogCollection(piPartColl, piPartObj, L"Applications", ppiAppColl); + ExitOnFailure(hr, "Failed to get catalog collection for partition"); + } + + // COM+ pre 1.5 + else + { + // this version of COM+ does not support partitions, make sure a partition was not specified + if (pwzPartID && *pwzPartID) + ExitOnFailure(hr = E_FAIL, "Partitions are not supported by this version of COM+"); + + // get applications collection + hr = CpiExecGetCatalogCollection(L"Applications", ppiAppColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + } + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCatalog); + ReleaseObject(piCatalog2); + ReleaseBSTR(bstrGlobPartID); + + ReleaseObject(piPartColl); + ReleaseObject(piPartObj); + + return hr; +} + +HRESULT CpiGetRolesCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + ICatalogCollection** ppiRolesColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piAppColl = NULL; + ICatalogObject* piAppObj = NULL; + + // get applications collection + hr = CpiExecGetApplicationsCollection(pwzPartID, &piAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + + if (S_FALSE == hr) + ExitFunction(); // applications collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByStringKey(piAppColl, pwzAppID, &piAppObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // application not found, exit with hr = S_FALSE + + // get roles collection + hr = CpiExecGetCatalogCollection(piAppColl, piAppObj, L"Roles", ppiRolesColl); + ExitOnFailure(hr, "Failed to catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppColl); + ReleaseObject(piAppObj); + + return hr; +} + +HRESULT CpiGetUsersInRoleCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + LPCWSTR pwzRoleName, + ICatalogCollection** ppiUsrInRoleColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piRoleColl = NULL; + ICatalogObject* piRoleObj = NULL; + + // get roles collection + hr = CpiGetRolesCollection(pwzPartID, pwzAppID, &piRoleColl); + ExitOnFailure(hr, "Failed to get roles collection"); + + if (S_FALSE == hr) + ExitFunction(); // roles collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByName(piRoleColl, pwzRoleName, &piRoleObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // role not found, exit with hr = S_FALSE + + // get roles collection + hr = CpiExecGetCatalogCollection(piRoleColl, piRoleObj, L"UsersInRole", ppiUsrInRoleColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piRoleColl); + ReleaseObject(piRoleObj); + + return hr; +} + +HRESULT CpiGetComponentsCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + ICatalogCollection** ppiCompsColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piAppColl = NULL; + ICatalogObject* piAppObj = NULL; + + // get applications collection + hr = CpiExecGetApplicationsCollection(pwzPartID, &piAppColl); + ExitOnFailure(hr, "Failed to get applications collection"); + + if (S_FALSE == hr) + ExitFunction(); // applications collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByStringKey(piAppColl, pwzAppID, &piAppObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // application not found, exit with hr = S_FALSE + + // get components collection + hr = CpiExecGetCatalogCollection(piAppColl, piAppObj, L"Components", ppiCompsColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piAppColl); + ReleaseObject(piAppObj); + + return hr; +} + +HRESULT CpiGetInterfacesCollection( + ICatalogCollection* piCompColl, + ICatalogObject* piCompObj, + ICatalogCollection** ppiIntfColl + ) +{ + HRESULT hr = S_OK; + + // get interfaces collection + hr = CpiExecGetCatalogCollection(piCompColl, piCompObj, L"InterfacesForComponent", ppiIntfColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetMethodsCollection( + ICatalogCollection* piIntfColl, + ICatalogObject* piIntfObj, + ICatalogCollection** ppiMethColl + ) +{ + HRESULT hr = S_OK; + + // get interfaces collection + hr = CpiExecGetCatalogCollection(piIntfColl, piIntfObj, L"MethodsForInterface", ppiMethColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiGetSubscriptionsCollection( + LPCWSTR pwzPartID, + LPCWSTR pwzAppID, + LPCWSTR pwzCompCLSID, + ICatalogCollection** ppiSubsColl + ) +{ + HRESULT hr = S_OK; + + ICatalogCollection* piCompColl = NULL; + ICatalogObject* piCompObj = NULL; + + // get components collection + hr = CpiGetComponentsCollection(pwzPartID, pwzAppID, &piCompColl); + ExitOnFailure(hr, "Failed to get components collection"); + + if (S_FALSE == hr) + ExitFunction(); // components collection not found, exit with hr = S_FALSE + + // find object + hr = CpiFindCollectionObjectByStringKey(piCompColl, pwzCompCLSID, &piCompObj); + ExitOnFailure(hr, "Failed to find collection object"); + + if (S_FALSE == hr) + ExitFunction(); // component not found, exit with hr = S_FALSE + + // get subscriptions collection + hr = CpiExecGetCatalogCollection(piCompColl, piCompObj, L"SubscriptionsForComponent", ppiSubsColl); + ExitOnFailure(hr, "Failed to get catalog collection"); + + hr = S_OK; + +LExit: + // clean up + ReleaseObject(piCompColl); + ReleaseObject(piCompObj); + + return hr; +} + +HRESULT CpiReadPropertyList( + LPWSTR* ppwzData, + CPI_PROPERTY** ppPropList + ) +{ + HRESULT hr = S_OK; + + CPI_PROPERTY* pItm = NULL; + LPWSTR pwzName = NULL; + + // clear list if it already contains items + if (*ppPropList) + CpiFreePropertyList(*ppPropList); + *ppPropList = NULL; + + // read property count + int iPropCnt = 0; + hr = WcaReadIntegerFromCaData(ppwzData, &iPropCnt); + ExitOnFailure(hr, "Failed to read property count"); + + for (int i = 0; i < iPropCnt; i++) + { + // allocate new element + pItm = (CPI_PROPERTY*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PROPERTY)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // Name + hr = WcaReadStringFromCaData(ppwzData, &pwzName); + ExitOnFailure(hr, "Failed to read name"); + StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzName); + + // Value + hr = WcaReadStringFromCaData(ppwzData, &pItm->pwzValue); + ExitOnFailure(hr, "Failed to read property value"); + + // add to list + if (*ppPropList) + pItm->pNext = *ppPropList; + *ppPropList = pItm; + pItm = NULL; + } + + hr = S_OK; + +LExit: + // clean up + ReleaseStr(pwzName); + + if (pItm) + CpiFreePropertyList(pItm); + + return hr; +} + +void CpiFreePropertyList( + CPI_PROPERTY* pList + ) +{ + while (pList) + { + ReleaseStr(pList->pwzValue); + + CPI_PROPERTY* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +HRESULT CpiWriteKeyToRollbackFile( + HANDLE hFile, + LPCWSTR pwzKey + ) +{ + HRESULT hr = S_OK; + + WCHAR wzKey[MAX_DARWIN_KEY + 1]; + ::ZeroMemory(wzKey, sizeof(wzKey)); + hr = StringCchCopyW(wzKey, countof(wzKey), pwzKey); + ExitOnFailure(hr, "Failed to copy key"); + + hr = WriteFileAll(hFile, (PBYTE)wzKey, MAX_DARWIN_KEY * sizeof(WCHAR)); + ExitOnFailure(hr, "Failed to write buffer"); + + FlushFileBuffers(hFile); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiWriteIntegerToRollbackFile( + HANDLE hFile, + int i + ) +{ + HRESULT hr = S_OK; + + hr = WriteFileAll(hFile, (PBYTE)&i, sizeof(int)); + ExitOnFailure(hr, "Failed to write buffer"); + + FlushFileBuffers(hFile); + + hr = S_OK; + +LExit: + return hr; +} + +HRESULT CpiReadRollbackDataList( + HANDLE hFile, + CPI_ROLLBACK_DATA** pprdList + ) +{ + HRESULT hr = S_OK; + + int iCount; + + CPI_ROLLBACK_DATA* pItm = NULL; + + // read count + hr = ReadFileAll(hFile, (PBYTE)&iCount, sizeof(int)); + if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr) + ExitFunction1(hr = S_OK); // EOF reached, nothing left to read + ExitOnFailure(hr, "Failed to read count"); + + for (int i = 0; i < iCount; i++) + { + // allocate new element + pItm = (CPI_ROLLBACK_DATA*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_ROLLBACK_DATA)); + if (!pItm) + ExitFunction1(hr = E_OUTOFMEMORY); + + // read from file + hr = ReadFileAll(hFile, (PBYTE)pItm->wzKey, MAX_DARWIN_KEY * sizeof(WCHAR)); + if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr) + break; // EOF reached, nothing left to read + ExitOnFailure(hr, "Failed to read key"); + + hr = ReadFileAll(hFile, (PBYTE)&pItm->iStatus, sizeof(int)); + if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr) + pItm->iStatus = 0; // EOF reached, the operation was interupted; set status to zero + else + ExitOnFailure(hr, "Failed to read status"); + + // add to list + if (*pprdList) + pItm->pNext = *pprdList; + *pprdList = pItm; + pItm = NULL; + } + + hr = S_OK; + +LExit: + // clean up + if (pItm) + CpiFreeRollbackDataList(pItm); + + return hr; +} + +void CpiFreeRollbackDataList( + CPI_ROLLBACK_DATA* pList + ) +{ + while (pList) + { + CPI_ROLLBACK_DATA* pDelete = pList; + pList = pList->pNext; + ::HeapFree(::GetProcessHeap(), 0, pDelete); + } +} + +HRESULT CpiFindRollbackStatus( + CPI_ROLLBACK_DATA* pList, + LPCWSTR pwzKey, + int* piStatus + ) +{ + HRESULT hr = S_OK; + + for (; pList; pList = pList->pNext) + { + if (0 == lstrcmpW(pList->wzKey, pwzKey)) + { + *piStatus = pList->iStatus; + ExitFunction1(hr = S_OK); + } + } + + hr = S_FALSE; + +LExit: + return hr; +} + +HRESULT CpiAccountNameToSid( + LPCWSTR pwzAccountName, + PSID* ppSid + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + NTSTATUS st = 0; + + PSID pSid = NULL; + LSA_OBJECT_ATTRIBUTES loaAttributes; + LSA_HANDLE lsahPolicy = NULL; + LSA_UNICODE_STRING lusName; + PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL; + PLSA_TRANSLATED_SID pltsSid = NULL; + + ::ZeroMemory(&loaAttributes, sizeof(loaAttributes)); + ::ZeroMemory(&lusName, sizeof(lusName)); + + // identify well known SIDs + for (CPI_WELLKNOWN_SID* pWS = wsWellKnownSids; pWS->pwzName; pWS++) + { + if (0 == lstrcmpiW(pwzAccountName, pWS->pwzName)) + { + // allocate SID buffer + pSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, ::GetSidLengthRequired(pWS->nSubAuthorityCount)); + ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID"); + + // initialize SID + ::InitializeSid(pSid, &pWS->iaIdentifierAuthority, pWS->nSubAuthorityCount); + + // copy sub autorities + for (DWORD i = 0; i < pWS->nSubAuthorityCount; i++) + *::GetSidSubAuthority(pSid, i) = pWS->dwSubAuthority[i]; + + break; + } + } + + // lookup name + if (!pSid) + { + // open policy handle + st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle"); + + // create account name lsa unicode string + hr = InitLsaUnicodeString(&lusName, pwzAccountName, (DWORD)wcslen(pwzAccountName)); + ExitOnFailure(hr, "Failed to initialize account name string"); + + // lookup name + st = ::LsaLookupNames(lsahPolicy, 1, &lusName, &plrdsDomains, &pltsSid); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names"); + + if (SidTypeDomain == pltsSid->Use) + ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported"); + + // convert sid + hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pSid); + ExitOnFailure(hr, "Failed to convert SID"); + } + + *ppSid = pSid; + pSid = NULL; + + hr = S_OK; + +LExit: + // clean up + if (pSid) + ::HeapFree(::GetProcessHeap(), 0, pSid); + if (lsahPolicy) + ::LsaClose(lsahPolicy); + if (plrdsDomains) + ::LsaFreeMemory(plrdsDomains); + if (pltsSid) + ::LsaFreeMemory(pltsSid); + FreeLsaUnicodeString(&lusName); + + return hr; +} + +HRESULT CpiSidToAccountName( + PSID pSid, + LPWSTR* ppwzAccountName + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + NTSTATUS st = 0; + + LSA_OBJECT_ATTRIBUTES loaAttributes; + LSA_HANDLE lsahPolicy = NULL; + PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL; + PLSA_TRANSLATED_NAME pltnName = NULL; + + LPWSTR pwzDomain = NULL; + LPWSTR pwzName = NULL; + + ::ZeroMemory(&loaAttributes, sizeof(loaAttributes)); + + // open policy handle + st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle"); + + // lookup SID + st = ::LsaLookupSids(lsahPolicy, 1, &pSid, &plrdsDomains, &pltnName); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed lookup SID"); + + if (SidTypeDomain == pltnName->Use) + ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported"); + + // format account name string + if (SidTypeWellKnownGroup != pltnName->Use) + { + PLSA_UNICODE_STRING plusDomain = &plrdsDomains->Domains[pltnName->DomainIndex].Name; + hr = StrAllocString(&pwzDomain, plusDomain->Buffer, plusDomain->Length / sizeof(WCHAR)); + ExitOnFailure(hr, "Failed to allocate name string"); + } + + hr = StrAllocString(&pwzName, pltnName->Name.Buffer, pltnName->Name.Length / sizeof(WCHAR)); + ExitOnFailure(hr, "Failed to allocate domain string"); + + hr = StrAllocFormatted(ppwzAccountName, L"%s\\%s", pwzDomain ? pwzDomain : L"", pwzName); + ExitOnFailure(hr, "Failed to format account name string"); + + hr = S_OK; + +LExit: + // clean up + if (lsahPolicy) + ::LsaClose(lsahPolicy); + if (plrdsDomains) + ::LsaFreeMemory(plrdsDomains); + if (pltnName) + ::LsaFreeMemory(pltnName); + + ReleaseStr(pwzDomain); + ReleaseStr(pwzName); + + return hr; +} + +// helper function definitions + +static HRESULT FindUserCollectionObjectIndex( + ICatalogCollection* piColl, + PSID pSid, + int* pi + ) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + NTSTATUS st = 0; + + long i = 0; + long lCollCnt = 0; + + LSA_OBJECT_ATTRIBUTES loaAttributes; + LSA_HANDLE lsahPolicy = NULL; + PLSA_UNICODE_STRING plusNames = NULL; + PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL; + PLSA_TRANSLATED_SID pltsSids = NULL; + + IDispatch* piDisp = NULL; + ICatalogObject* piObj = NULL; + VARIANT vtVal; + + PSID pTmpSid = NULL; + + PLSA_TRANSLATED_SID pltsSid; + + ::VariantInit(&vtVal); + ::ZeroMemory(&loaAttributes, sizeof(loaAttributes)); + + // open policy handle + st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy); + er = ::LsaNtStatusToWinError(st); + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle"); + + // get number of elements in collection + hr = piColl->get_Count(&lCollCnt); + ExitOnFailure(hr, "Failed to get to number of objects in collection"); + + if (0 == lCollCnt) + ExitFunction1(hr = S_FALSE); // not found + + // allocate name buffer + plusNames = (PLSA_UNICODE_STRING)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LSA_UNICODE_STRING) * lCollCnt); + ExitOnNull(plusNames, hr, E_OUTOFMEMORY, "Failed to allocate names buffer"); + + // get accounts in collection + for (i = 0; i < lCollCnt; i++) + { + // get ICatalogObject interface + hr = piColl->get_Item(i, &piDisp); + ExitOnFailure(hr, "Failed to get object from collection"); + + hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); + ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); + + // get value + hr = piObj->get_Key(&vtVal); + ExitOnFailure(hr, "Failed to get key"); + + hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); + ExitOnFailure(hr, "Failed to change variant type"); + + // copy account name string + hr = InitLsaUnicodeString(&plusNames[i], vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal)); + ExitOnFailure(hr, "Failed to initialize account name string"); + + // clean up + ReleaseNullObject(piDisp); + ReleaseNullObject(piObj); + ::VariantClear(&vtVal); + } + + // lookup names + st = ::LsaLookupNames(lsahPolicy, lCollCnt, plusNames, &plrdsDomains, &pltsSids); + er = ::LsaNtStatusToWinError(st); + if (ERROR_NONE_MAPPED != er && ERROR_SOME_NOT_MAPPED != er) + ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names"); + + // compare SIDs + for (i = 0; i < lCollCnt; i++) + { + // get SID + pltsSid = &pltsSids[i]; + if (SidTypeDomain == pltsSid->Use || SidTypeInvalid == pltsSid->Use || SidTypeUnknown == pltsSid->Use) + continue; // ignore... + + hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pTmpSid); + ExitOnFailure(hr, "Failed to convert SID"); + + // compare SIDs + if (::EqualSid(pSid, pTmpSid)) + { + *pi = i; + ExitFunction1(hr = S_OK); + } + } + + if (ERROR_NONE_MAPPED == er || ERROR_SOME_NOT_MAPPED == er) + hr = HRESULT_FROM_WIN32(er); + else + hr = S_FALSE; // not found + +LExit: + // clean up + ReleaseObject(piDisp); + ReleaseObject(piObj); + ::VariantClear(&vtVal); + + if (plusNames) + { + for (i = 0; i < lCollCnt; i++) + FreeLsaUnicodeString(&plusNames[i]); + ::HeapFree(::GetProcessHeap(), 0, plusNames); + } + + if (lsahPolicy) + ::LsaClose(lsahPolicy); + if (plrdsDomains) + ::LsaFreeMemory(plrdsDomains); + if (pltsSids) + ::LsaFreeMemory(pltsSids); + + if (pTmpSid) + ::HeapFree(::GetProcessHeap(), 0, pTmpSid); + + return hr; +} + +static HRESULT CreateSidFromDomainRidPair( + PSID pDomainSid, + DWORD dwRid, + PSID* ppSid + ) +{ + HRESULT hr = S_OK; + PSID pSid = NULL; + + // get domain SID sub authority count + UCHAR ucSubAuthorityCount = *::GetSidSubAuthorityCount(pDomainSid); + + // allocate SID buffer + DWORD dwLengthRequired = ::GetSidLengthRequired(ucSubAuthorityCount + (UCHAR)1); + if (*ppSid) + { + SIZE_T ccb = ::HeapSize(::GetProcessHeap(), 0, *ppSid); + if (-1 == ccb) + ExitOnFailure(hr = E_FAIL, "Failed to get size of SID buffer"); + + if (ccb < dwLengthRequired) + { + pSid = (PSID)::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, *ppSid, dwLengthRequired); + ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to reallocate buffer for SID, len: %d", dwLengthRequired); + *ppSid = pSid; + } + } + else + { + *ppSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwLengthRequired); + ExitOnNull(*ppSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID, len: %d", dwLengthRequired); + } + + ::InitializeSid(*ppSid, ::GetSidIdentifierAuthority(pDomainSid), ucSubAuthorityCount + (UCHAR)1); + + // copy sub autorities + DWORD i = 0; + for (; i < ucSubAuthorityCount; i++) + *::GetSidSubAuthority(*ppSid, i) = *::GetSidSubAuthority(pDomainSid, i); + *::GetSidSubAuthority(*ppSid, i) = dwRid; + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT InitLsaUnicodeString( + PLSA_UNICODE_STRING plusStr, + LPCWSTR pwzStr, + DWORD dwLen + ) +{ + HRESULT hr = S_OK; + + plusStr->Length = (USHORT)dwLen * sizeof(WCHAR); + plusStr->MaximumLength = (USHORT)(dwLen + 1) * sizeof(WCHAR); + + plusStr->Buffer = (WCHAR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * (dwLen + 1)); + ExitOnNull(plusStr->Buffer, hr, E_OUTOFMEMORY, "Failed to allocate account name string"); + + hr = StringCchCopyW(plusStr->Buffer, dwLen + 1, pwzStr); + ExitOnFailure(hr, "Failed to copy buffer"); + + hr = S_OK; + +LExit: + return hr; +} + +static void FreeLsaUnicodeString( + PLSA_UNICODE_STRING plusStr + ) +{ + if (plusStr->Buffer) + ::HeapFree(::GetProcessHeap(), 0, plusStr->Buffer); +} + +static HRESULT WriteFileAll( + HANDLE hFile, + PBYTE pbBuffer, + DWORD dwBufferLength + ) +{ + HRESULT hr = S_OK; + + DWORD dwBytesWritten; + + while (dwBufferLength) + { + if (!::WriteFile(hFile, pbBuffer, dwBufferLength, &dwBytesWritten, NULL)) + ExitFunction1(hr = HRESULT_FROM_WIN32(::GetLastError())); + + dwBufferLength -= dwBytesWritten; + pbBuffer += dwBytesWritten; + } + + hr = S_OK; + +LExit: + return hr; +} + +static HRESULT ReadFileAll( + HANDLE hFile, + PBYTE pbBuffer, + DWORD dwBufferLength + ) +{ + HRESULT hr = S_OK; + + DWORD dwBytesRead; + + while (dwBufferLength) + { + if (!::ReadFile(hFile, pbBuffer, dwBufferLength, &dwBytesRead, NULL)) + ExitFunction1(hr = HRESULT_FROM_WIN32(::GetLastError())); + + if (0 == dwBytesRead) + ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF)); + + dwBufferLength -= dwBytesRead; + pbBuffer += dwBytesRead; + } + + hr = S_OK; + +LExit: + return hr; +} -- cgit v1.2.3-55-g6feb