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