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; }
static HRESULT ReadApplicationRoleAttributes( LPWSTR* ppwzData, CPI_APPLICATION_ROLE_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); ExitOnFailure(hr, "Failed to read action type"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); ExitOnFailure(hr, "Failed to read action cost"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); ExitOnFailure(hr, "Failed to read key"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName); ExitOnFailure(hr, "Failed to read name"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID); ExitOnFailure(hr, "Failed to read application id"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); ExitOnFailure(hr, "Failed to read partition id"); hr = CpiReadPropertyList(ppwzData, &pAttrs->pPropList); ExitOnFailure(hr, "Failed to read properties"); hr = S_OK; LExit: return hr; }
static HRESULT ReadMessageQueueAttributes( LPWSTR* ppwzData, MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; // read message queue information from custom action data hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); ExitOnFailure(hr, "Failed to read key from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iBasePriority); ExitOnFailure(hr, "Failed to read base priority from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iJournalQuota); ExitOnFailure(hr, "Failed to read journal quota from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzLabel); ExitOnFailure(hr, "Failed to read label from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzMulticastAddress); ExitOnFailure(hr, "Failed to read multicast address from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPathName); ExitOnFailure(hr, "Failed to read path name from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iPrivLevel); ExitOnFailure(hr, "Failed to read privacy level from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iQuota); ExitOnFailure(hr, "Failed to read quota from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzServiceTypeGuid); ExitOnFailure(hr, "Failed to read service type guid from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iAttributes); ExitOnFailure(hr, "Failed to read attributes from custom action data"); hr = S_OK; LExit: return hr; }
static HRESULT ReadUsersInApplicationRoleAttributes( LPWSTR* ppwzData, CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); ExitOnFailure(hr, "Failed to read action type"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); ExitOnFailure(hr, "Failed to read action cost"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); ExitOnFailure(hr, "Failed to read key"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzRoleName); ExitOnFailure(hr, "Failed to read role name"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount); ExitOnFailure(hr, "Failed to read account name"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAppID); ExitOnFailure(hr, "Failed to read application id"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); ExitOnFailure(hr, "Failed to read partition id"); hr = S_OK; LExit: 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; }
/****************************************************************** WixRollbackInternetShortcuts - entry point for Internet shortcuts custom action (rollback) *******************************************************************/ extern "C" UINT __stdcall WixRollbackInternetShortcuts( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwz = NULL; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzShortcutPath = NULL; int iAttr = 0; // initialize hr = WcaInitialize(hInstall, "WixRemoveInternetShortcuts"); ExitOnFailure(hr, "failed to initialize WixRemoveInternetShortcuts"); hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); // loop through all the custom action data pwz = pwzCustomActionData; while (pwz && *pwz) { // extract the custom action data we're interested in hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath); ExitOnFailure(hr, "failed to read shortcut path from custom action data for rollback"); // delete file hr = FileEnsureDelete(pwzShortcutPath); ExitOnFailure1(hr, "failed to delete file '%ls'", pwzShortcutPath); // skip over the shortcut target and attributes hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath); ExitOnFailure(hr, "failed to skip shortcut target from custom action data for rollback"); hr = WcaReadIntegerFromCaData(&pwz, &iAttr); ExitOnFailure(hr, "failed to read shortcut attributes from custom action data"); } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzShortcutPath); er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er; return WcaFinalize(er); }
/****************************************************************** ExecNetFx - entry point for NetFx Custom Action *******************************************************************/ extern "C" UINT __stdcall ExecNetFx( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug ExecNetFx"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzData = NULL; LPWSTR pwz = NULL; int iCost = 0; // initialize hr = WcaInitialize(hInstall, "ExecNetFx"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; // loop through all the passed in data while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzData); ExitOnFailure(hr, "failed to read command line from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iCost); ExitOnFailure(hr, "failed to read cost from custom action data"); hr = QuietExec(pwzData, NGEN_TIMEOUT); // If we fail here it isn't critical - keep looping through to try to act on the other assemblies on our list if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "failed to execute Ngen command (with error 0x%x): %ls, continuing anyway", hr, pwzData); hr = S_OK; } // Tick the progress bar along for this assembly hr = WcaProgressMessage(iCost, FALSE); ExitOnFailure1(hr, "failed to tick progress bar for command line: %ls", pwzData); } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
static HRESULT ReadPartitionUserAttributes( LPWSTR* ppwzData, CPI_PARTITION_USER_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionType); ExitOnFailure(hr, "Failed to read action type"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iActionCost); ExitOnFailure(hr, "Failed to read action cost"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); ExitOnFailure(hr, "Failed to read key"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzAccount); ExitOnFailure(hr, "Failed to read account name"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPartID); ExitOnFailure(hr, "Failed to read partition id"); hr = S_OK; LExit: return hr; }
static HRESULT ReadMessageQueuePermissionAttributes( LPWSTR* ppwzData, MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; // read message queue permission information from custom action data hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); ExitOnFailure(hr, "Failed to read key from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPathName); ExitOnFailure(hr, "Failed to read path name from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzDomain); ExitOnFailure(hr, "Failed to read domain from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName); ExitOnFailure(hr, "Failed to read name from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iPermissions); ExitOnFailure(hr, "Failed to read permissions from custom action data"); hr = S_OK; LExit: return hr; }
/******************************************************************** ConfigureIIsExec - custom action for installing IIs settings - table data will be wrapped and passed in from immediate CA ReadIIsTables ********************************************************************/ extern "C" UINT __stdcall ConfigureIIsExec( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ConfigureIIsExec here"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; BOOL fInitializedCom = FALSE; IMSAdminBase* piMetabase = NULL; SCA_WEB* pswList = NULL; SCA_WEBDIR* pswdList = NULL; SCA_VDIR* psvdList = NULL; SCA_FILTER* psfList = NULL; SCA_APPPOOL *psapList = NULL; SCA_MIMEMAP* psmmList = NULL; SCA_HTTP_HEADER* pshhList = NULL; SCA_PROPERTY *pspList = NULL; SCA_WEBSVCEXT* psWseList = NULL; SCA_WEB_ERROR* psweList = NULL; LPWSTR pwzScriptKey = NULL; LPWSTR pwzCustomActionData = NULL; WCA_WRAPQUERY_HANDLE hUserQuery = NULL; WCA_WRAPQUERY_HANDLE hWebBaseQuery = NULL; WCA_WRAPQUERY_HANDLE hWebDirPropQuery = NULL; WCA_WRAPQUERY_HANDLE hSslCertQuery = NULL; WCA_WRAPQUERY_HANDLE hWebLogQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppExtQuery = NULL; // initialize hr = WcaInitialize(hInstall, "ConfigureIIsExec"); ExitOnFailure(hr, "Failed to initialize"); hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); // Get the CaScript key hr = WcaReadStringFromCaData(&pwzCustomActionData, &pwzScriptKey); ExitOnFailure(hr, "Failed to get CaScript key from custom action data"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to initialize COM"); fInitializedCom = TRUE; // if IIS was uninstalled (thus no IID_IMSAdminBase) allow the // user to still uninstall this package by clicking "Ignore" do { hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void**)&piMetabase); if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "failed to get IID_IMSAdminBase Object"); er = WcaErrorMessage(msierrIISCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction(); // bail with the error result from the CoCreate to kick off a rollback case IDRETRY: hr = S_FALSE; // hit me, baby, one more time break; case IDIGNORE: __fallthrough; default: WcaLog(LOGMSG_STANDARD, "ignoring absent IIS"); // We need to write the empty script to communicate to other deferred CA that there is noting to do. hr = ScaWriteConfigurationScript(pwzScriptKey); ExitOnFailure(hr, "failed to schedule metabase configuration"); ExitFunction1(hr = S_OK); // pretend everything is okay break; } } } while (S_FALSE == hr); // read the msi tables hr = WcaBeginUnwrapQuery(&hUserQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap user query"); hr = ScaWebSvcExtRead(&psWseList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSvcExt, "failed while processing WebServiceExtensions"); hr = ScaAppPoolRead(&psapList, hUserQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadAppPool, "failed while processing WebAppPools"); // MimeMap, Error and HttpHeader need to be read before the virtual directory and web read hr = ScaMimeMapRead(&psmmList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadMimeMap, "failed while processing MimeMaps"); hr = ScaHttpHeaderRead(&pshhList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadHttpHeader, "failed while processing HttpHeaders"); hr = ScaWebErrorRead(&psweList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebError, "failed while processing WebErrors"); hr = WcaBeginUnwrapQuery(&hWebDirPropQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web dir properties query"); hr = WcaBeginUnwrapQuery(&hSslCertQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap ssl certificate query"); hr = WcaBeginUnwrapQuery(&hWebLogQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web log query"); hr = WcaBeginUnwrapQuery(&hWebAppQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application query"); hr = WcaBeginUnwrapQuery(&hWebAppExtQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application extension query"); hr = ScaWebsRead(piMetabase, &psmmList, &pswList, &pshhList, &psweList, hUserQuery, hWebDirPropQuery, hSslCertQuery, hWebLogQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSite, "failed while processing WebSites"); hr = WcaBeginUnwrapQuery(&hWebBaseQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web base query"); hr = ScaWebDirsRead(piMetabase, pswList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData, &pswdList); MessageExitOnFailure(hr, msierrIISFailedReadWebDirs, "failed while processing WebDirs"); hr = ScaVirtualDirsRead(piMetabase, pswList, &psvdList, &psmmList, &pshhList, &psweList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadVDirs, "failed while processing WebVirtualDirs"); hr = ScaFiltersRead(piMetabase, pswList, hWebBaseQuery, &psfList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadFilters, "failed while processing WebFilters"); hr = ScaPropertyRead(&pspList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadProp, "failed while processing WebProperties"); // do uninstall actions (order is important!) hr = ScaPropertyUninstall(piMetabase, pspList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallProp, "failed to uninstall IIS properties"); hr = ScaFiltersUninstall(piMetabase, psfList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallFilters, "failed to schedule uninstall of filters"); hr = ScaVirtualDirsUninstall(piMetabase, psvdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallVDirs, "failed to schedule uninstall of virtual directories"); hr = ScaWebDirsUninstall(piMetabase, pswdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebDirs, "failed to schedule uninstall of web directories"); hr = ScaWebsUninstall(piMetabase, pswList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebs, "failed to schedule uninstall of webs"); hr = ScaAppPoolUninstall(piMetabase, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallAppPool, "failed to schedule uninstall of AppPools"); // do install actions (order is important!) // ScaWebSvcExtCommit contains both uninstall and install actions. hr = ScaWebSvcExtCommit(piMetabase, psWseList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebSvcExt, "failed to schedule install/uninstall of WebSvcExt"); hr = ScaAppPoolInstall(piMetabase, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallAppPool, "failed to schedule install of AppPools"); hr = ScaWebsInstall(piMetabase, pswList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebs, "failed to schedule install of webs"); hr = ScaWebDirsInstall(piMetabase, pswdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebDirs, "failed to schedule install of web directories"); hr = ScaVirtualDirsInstall(piMetabase, psvdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallVDirs, "failed to schedule install of virtual directories"); hr = ScaFiltersInstall(piMetabase, psfList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallFilters, "failed to schedule install of filters"); hr = ScaPropertyInstall(piMetabase, pspList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallProp, "failed to schedule install of properties"); hr = ScaWriteConfigurationScript(pwzScriptKey); ExitOnFailure(hr, "failed to schedule metabase configuration"); LExit: ReleaseStr(pwzScriptKey); ReleaseStr(pwzCustomActionData); WcaFinishUnwrapQuery(hUserQuery); WcaFinishUnwrapQuery(hWebBaseQuery); WcaFinishUnwrapQuery(hWebDirPropQuery); WcaFinishUnwrapQuery(hSslCertQuery); WcaFinishUnwrapQuery(hWebLogQuery); WcaFinishUnwrapQuery(hWebAppQuery); WcaFinishUnwrapQuery(hWebAppExtQuery); if (psWseList) { ScaWebSvcExtFreeList(psWseList); } if (psfList) { ScaFiltersFreeList(psfList); } if (psvdList) { ScaVirtualDirsFreeList(psvdList); } if (pswdList) { ScaWebDirsFreeList(pswdList); } if (pswList) { ScaWebsFreeList(pswList); } if (psmmList) { ScaMimeMapCheckList(psmmList); ScaMimeMapFreeList(psmmList); } if (pshhList) { ScaHttpHeaderCheckList(pshhList); ScaHttpHeaderFreeList(pshhList); } if (psweList) { ScaWebErrorCheckList(psweList); ScaWebErrorFreeList(psweList); } ReleaseObject(piMetabase); if (fInitializedCom) { ::CoUninitialize(); } er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/******************************************************************** ComPlusRollbackUninstallExecute - CUSTOM ACTION ENTRY POINT Input: deferred CustomActionData - ComPlusRollbackUninstallExecute ********************************************************************/ extern "C" UINT __stdcall ComPlusRollbackUninstallExecute(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzData = NULL; LPWSTR pwzRollbackFileName = NULL; HANDLE hRollbackFile = INVALID_HANDLE_VALUE; CPI_ROLLBACK_DATA* prdPartitions = NULL; CPI_ROLLBACK_DATA* prdUsersInPartitionRoles = NULL; CPI_ROLLBACK_DATA* prdPartitionUsers = NULL; CPI_ROLLBACK_DATA* prdApplications = NULL; CPI_ROLLBACK_DATA* prdApplicationRoles = NULL; CPI_ROLLBACK_DATA* prdUsersApplicationRoles = NULL; CPI_ROLLBACK_DATA* prdAssemblies = NULL; CPI_ROLLBACK_DATA* prdRoleAssignments = NULL; CPI_ROLLBACK_DATA* prdSubscriptions = NULL; BOOL fInitializedCom = FALSE; // initialize hr = WcaInitialize(hInstall, "ComPlusRollbackUninstallExecute"); ExitOnFailure(hr, "Failed to initialize ComPlusRollbackUninstallExecute"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; CpiInitialize(); // get custom action data hr = WcaGetProperty(L"CustomActionData", &pwzData); ExitOnFailure(hr, "Failed to get CustomActionData"); // open rollback file hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName); ExitOnFailure(hr, "Failed to read rollback file name"); hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); if (INVALID_HANDLE_VALUE == hRollbackFile) ExitOnFailure1(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName); // read rollback data hr = CpiReadRollbackDataList(hRollbackFile, &prdSubscriptions); ExitOnFailure(hr, "Failed to read subscription rollback data"); hr = CpiReadRollbackDataList(hRollbackFile, &prdRoleAssignments); ExitOnFailure(hr, "Failed to read role assignments rollback data"); hr = CpiReadRollbackDataList(hRollbackFile, &prdAssemblies); ExitOnFailure(hr, "Failed to read assemblies rollback data"); hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersApplicationRoles); ExitOnFailure(hr, "Failed to read users in application roles rollback data"); hr = CpiReadRollbackDataList(hRollbackFile, &prdApplicationRoles); ExitOnFailure(hr, "Failed to read application roles rollback data"); hr = CpiReadRollbackDataList(hRollbackFile, &prdApplications); ExitOnFailure(hr, "Failed to read applications rollback data"); hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitionUsers); ExitOnFailure(hr, "Failed to read partition users rollback data"); hr = CpiReadRollbackDataList(hRollbackFile, &prdUsersInPartitionRoles); ExitOnFailure(hr, "Failed to read users in partition roles rollback data"); hr = CpiReadRollbackDataList(hRollbackFile, &prdPartitions); ExitOnFailure(hr, "Failed to read partitions rollback data"); ::CloseHandle(hRollbackFile); hRollbackFile = INVALID_HANDLE_VALUE; // rollback remove partitions hr = CpiRollbackConfigurePartitions(&pwzData, prdPartitions); ExitOnFailure(hr, "Failed to rollback delete partitions"); // rollback remove users in partition roles hr = CpiRollbackConfigureUsersInPartitionRoles(&pwzData, prdUsersInPartitionRoles); ExitOnFailure(hr, "Failed to rollback delete users in partition roles"); // rollback remove partition users hr = CpiRollbackConfigurePartitionUsers(&pwzData, prdPartitionUsers); ExitOnFailure(hr, "Failed to rollback delete partition users"); // rollback remove applications hr = CpiRollbackConfigureApplications(&pwzData, prdApplications); ExitOnFailure(hr, "Failed to rollback delete applications"); // rollback remove application roles hr = CpiRollbackConfigureApplicationRoles(&pwzData, prdApplicationRoles); ExitOnFailure(hr, "Failed to rollback delete application roles"); // rollback remove users in application roles hr = CpiRollbackConfigureUsersInApplicationRoles(&pwzData, prdUsersApplicationRoles); ExitOnFailure(hr, "Failed to rollback delete users in application roles"); // rollback unregister assemblies hr = CpiRollbackConfigureAssemblies(&pwzData, prdAssemblies); ExitOnFailure(hr, "Failed to rollback unregister assemblies"); // rollback delete role assignments hr = CpiRollbackConfigureRoleAssignments(&pwzData, prdAssemblies); ExitOnFailure(hr, "Failed to rollback delete role assignments"); // rollback delete subscriptions hr = CpiRollbackConfigureSubscriptions(&pwzData, prdSubscriptions); ExitOnFailure(hr, "Failed to rollback delete subscriptions"); hr = S_OK; LExit: // clean up ReleaseStr(pwzData); ReleaseStr(pwzRollbackFileName); if (INVALID_HANDLE_VALUE != hRollbackFile) ::CloseHandle(hRollbackFile); if (prdPartitions) CpiFreeRollbackDataList(prdPartitions); if (prdUsersInPartitionRoles) CpiFreeRollbackDataList(prdUsersInPartitionRoles); if (prdPartitionUsers) CpiFreeRollbackDataList(prdPartitionUsers); if (prdApplications) CpiFreeRollbackDataList(prdApplications); if (prdApplicationRoles) CpiFreeRollbackDataList(prdApplicationRoles); if (prdUsersApplicationRoles) CpiFreeRollbackDataList(prdUsersApplicationRoles); if (prdAssemblies) CpiFreeRollbackDataList(prdAssemblies); if (prdRoleAssignments) CpiFreeRollbackDataList(prdRoleAssignments); if (prdSubscriptions) CpiFreeRollbackDataList(prdSubscriptions); // unitialize CpiFinalize(); if (fInitializedCom) ::CoUninitialize(); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** WixCreateInternetShortcuts - entry point for Internet shortcuts custom action *******************************************************************/ extern "C" UINT __stdcall WixCreateInternetShortcuts( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwz = NULL; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzTarget = NULL; LPWSTR pwzShortcutPath = NULL; LPWSTR pwzIconPath = NULL; BOOL fInitializedCom = FALSE; int iAttr = 0; int iIconIndex = 0; // initialize hr = WcaInitialize(hInstall, "WixCreateInternetShortcuts"); ExitOnFailure(hr, "failed to initialize WixCreateInternetShortcuts"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to initialize COM"); fInitializedCom = TRUE; // extract the custom action data hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); // loop through all the custom action data pwz = pwzCustomActionData; while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzShortcutPath); ExitOnFailure(hr, "failed to read shortcut path from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzTarget); ExitOnFailure(hr, "failed to read shortcut target from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iAttr); ExitOnFailure(hr, "failed to read shortcut attributes from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzIconPath); ExitOnFailure(hr, "failed to read shortcut icon path from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iIconIndex); ExitOnFailure(hr, "failed to read shortcut icon index from custom action data"); if ((iAttr & esaURL) == esaURL) { hr = CreateUrl(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex); } else { hr = CreateLink(pwzTarget, pwzShortcutPath, pwzIconPath, iIconIndex); } ExitOnFailure(hr, "failed to create Internet shortcut"); // tick the progress bar hr = WcaProgressMessage(COST_INTERNETSHORTCUT, FALSE); ExitOnFailure1(hr, "failed to tick progress bar for shortcut: %ls", pwzShortcutPath); } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzTarget); ReleaseStr(pwzShortcutPath); if (fInitializedCom) { ::CoUninitialize(); } er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er; return WcaFinalize(er); }
extern "C" UINT __stdcall ExecSecureObjectsRollback( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug ExecSecureObjectsRollback"); HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; LPWSTR pwz = NULL; LPWSTR pwzData = NULL; LPWSTR pwzObject = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzSecurityInfo = NULL; SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; PSECURITY_DESCRIPTOR psd = NULL; ULONG psdSize; SECURITY_DESCRIPTOR_CONTROL sdc = {0}; SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; PACL pDacl = NULL; BOOL bDaclPresent = false; BOOL bDaclDefaulted = false; DWORD dwRevision = 0; int iProtected; // initialize hr = WcaInitialize(hInstall, "ExecSecureObjectsRollback"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty(L"CustomActionData", &pwzData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); pwz = pwzData; hr = WcaReadStringFromCaData(&pwz, &pwzObject); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzTable); ExitOnFailure(hr, "failed to process CustomActionData"); objectType = SEObjectTypeFromString(const_cast<LPCWSTR> (pwzTable)); if (SE_UNKNOWN_OBJECT_TYPE != objectType) { hr = WcaReadStringFromCaData(&pwz, &pwzSecurityInfo); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, &iProtected); ExitOnFailure(hr, "failed to process CustomActionData"); if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(pwzSecurityInfo,SDDL_REVISION_1,&psd,&psdSize)) { ExitOnLastError(hr, "failed to convert security descriptor string to a valid security descriptor"); } if (!::GetSecurityDescriptorDacl(psd,&bDaclPresent,&pDacl,&bDaclDefaulted)) { hr = E_UNEXPECTED; ExitOnFailure2(hr, "failed to get security descriptor's DACL - error code: %d",pwzSecurityInfo,GetLastError()); } // The below situation may always be caught by the above if block - the documentation isn't very clear. To be safe, we're going to test for it. if (!bDaclPresent) { hr = E_UNEXPECTED; ExitOnFailure(hr, "security descriptor does not contain a DACL"); } //Need to see if DACL is protected so getting Descriptor information if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) { ExitOnLastError1(hr, "failed to get security descriptor control for object: %ls", pwzObject); } // Write a 1 if DACL is protected, 0 otherwise switch (iProtected) { case 0: // Unnecessary to do anything - leave si to the default flags break; case 1: si = si | PROTECTED_DACL_SECURITY_INFORMATION; break; default: hr = E_UNEXPECTED; ExitOnFailure(hr, "unrecognized value in CustomActionData"); break; } er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pDacl, NULL); ExitOnFailure2(hr = HRESULT_FROM_WIN32(er), "failed to set security info for object: %ls error code: %d", pwzObject, GetLastError()); } else { MessageExitOnFailure1(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); } LExit: ReleaseStr(pwzData); ReleaseStr(pwzObject); ReleaseStr(pwzTable); ReleaseStr(pwzSecurityInfo); if (psd) { ::LocalFree(psd); } if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/******************************************************************** ComPlusInstallExecuteCommit - CUSTOM ACTION ENTRY POINT Input: deferred CustomActionData - ComPlusInstallExecuteCommit ********************************************************************/ extern "C" UINT __stdcall ComPlusInstallExecuteCommit(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzData = NULL; LPWSTR pwzRollbackFileName = NULL; HANDLE hRollbackFile = INVALID_HANDLE_VALUE; BOOL fInitializedCom = FALSE; // initialize hr = WcaInitialize(hInstall, "ComPlusInstallExecuteCommit"); ExitOnFailure(hr, "Failed to initialize ComPlusInstallExecuteCommit"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; CpiInitialize(); // get custom action data hr = WcaGetProperty(L"CustomActionData", &pwzData); ExitOnFailure(hr, "Failed to get CustomActionData"); // open rollback file hr = WcaReadStringFromCaData(&pwzData, &pwzRollbackFileName); ExitOnFailure(hr, "Failed to read rollback file name"); hRollbackFile = ::CreateFileW(pwzRollbackFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); if (INVALID_HANDLE_VALUE == hRollbackFile) ExitOnFailure1(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to open rollback file, name: %S", pwzRollbackFileName); if (INVALID_SET_FILE_POINTER == ::SetFilePointer(hRollbackFile, 0, NULL, FILE_END)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set file pointer"); // register assemblies hr = CpiConfigureAssemblies(&pwzData, hRollbackFile); ExitOnFailure(hr, "Failed to register assemblies"); if (S_FALSE == hr) ExitFunction(); // create role assignments hr = CpiConfigureRoleAssignments(&pwzData, hRollbackFile); ExitOnFailure(hr, "Failed to create role assignments"); if (S_FALSE == hr) ExitFunction(); // create subscriptions hr = CpiConfigureSubscriptions(&pwzData, hRollbackFile); ExitOnFailure(hr, "Failed to create subscriptions"); if (S_FALSE == hr) ExitFunction(); hr = S_OK; LExit: // clean up ReleaseStr(pwzData); if (INVALID_HANDLE_VALUE != hRollbackFile) ::CloseHandle(hRollbackFile); // unitialize CpiFinalize(); if (fInitializedCom) ::CoUninitialize(); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
static HRESULT ExecuteCertificateOperation( __in MSIHANDLE hInstall, __in SCA_ACTION saAction, __in DWORD dwStoreLocation ) { //AssertSz(FALSE, "Debug ExecuteCertificateOperation() here."); Assert(saAction & SCA_ACTION_INSTALL || saAction & SCA_ACTION_UNINSTALL); HRESULT hr = S_OK; LPWSTR pwzCaData = NULL; LPWSTR pwz; LPWSTR pwzName = NULL; LPWSTR pwzStore = NULL; int iAttributes = 0; LPWSTR pwzPFXPassword = NULL; LPWSTR pwzFilePath = NULL; BYTE* pbData = NULL; DWORD cbData = 0; HCERTSTORE hCertStore = NULL; hr = WcaGetProperty(L"CustomActionData", &pwzCaData); ExitOnFailure(hr, "Failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %S", pwzCaData); pwz = pwzCaData; hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "Failed to parse certificate name."); hr = WcaReadStringFromCaData(&pwz, &pwzStore); ExitOnFailure(hr, "Failed to parse CustomActionData, StoreName"); hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); ExitOnFailure(hr, "Failed to parse certificate attribute"); if (SCA_ACTION_INSTALL == saAction) // install operations need more data { if (iAttributes & SCA_CERT_INSTALLED_FILE_PATH) { hr = WcaReadStringFromCaData(&pwz, &pwzFilePath); ExitOnFailure(hr, "Failed to parse path to certficate file."); hr = FileReadUntil(&pbData, &cbData, pwzFilePath, SIXTY_FOUR_MEG); ExitOnFailure(hr, "Failed to read certificate from file path."); } else { hr = WcaReadStreamFromCaData(&pwz, &pbData, (DWORD_PTR*)&cbData); ExitOnFailure(hr, "Failed to parse certficate stream."); } hr = WcaReadStringFromCaData(&pwz, &pwzPFXPassword); ExitOnFailure(hr, "Failed to parse certificate password."); } // Open the right store. hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwStoreLocation, pwzStore); MessageExitOnNullWithLastError1(hCertStore, hr, msierrCERTFailedOpen, "Failed to open certificate store: %S", pwzStore); if (SCA_ACTION_INSTALL == saAction) // install operations need more data { hr = InstallCertificate(hCertStore, (dwStoreLocation == CERT_SYSTEM_STORE_CURRENT_USER), pwzName, pbData, cbData, pwzPFXPassword); ExitOnFailure(hr, "Failed to install certificate."); } else { Assert(SCA_ACTION_UNINSTALL == saAction); hr = UninstallCertificate(hCertStore, pwzName); ExitOnFailure(hr, "Failed to uninstall certificate."); } LExit: if (hCertStore) { ::CertCloseStore(hCertStore, 0); } ReleaseMem(pbData); ReleaseStr(pwzFilePath); ReleaseStr(pwzPFXPassword); ReleaseStr(pwzStore); ReleaseStr(pwzName); ReleaseStr(pwzCaData); return hr; }
/****************************************************************** CaExecServiceConfig - entry point for ServiceConfig Custom Action. NOTE: deferred CustomAction since it modifies the machine NOTE: CustomActionData == wzServiceName\tfNewService\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\tfNewService\t... *******************************************************************/ extern "C" UINT __stdcall ExecServiceConfig( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ExecServiceConfig"); HRESULT hr = S_OK; DWORD er = 0; LPWSTR pwzCustomActionData = NULL; LPWSTR pwz = NULL; LPWSTR pwzScriptKey = NULL; WCA_CASCRIPT_HANDLE hRollbackScript = NULL; LPWSTR pwzServiceName = NULL; BOOL fNewService = FALSE; LPWSTR pwzFirstFailureActionType = NULL; LPWSTR pwzSecondFailureActionType = NULL; LPWSTR pwzThirdFailureActionType = NULL; LPWSTR pwzProgramCommandLine = NULL; LPWSTR pwzRebootMessage = NULL; DWORD dwResetPeriodInDays = 0; DWORD dwRestartServiceDelayInSeconds = 0; LPVOID lpMsgBuf = NULL; SC_HANDLE hSCM = NULL; SC_HANDLE hService = NULL; DWORD dwRestartDelay = 0; WCHAR wzActionName[32] = { 0 }; DWORD cbExistingServiceConfig = 0; SERVICE_FAILURE_ACTIONSW* psfa = NULL; // initialize hr = WcaInitialize(hInstall, "ExecServiceConfig"); ExitOnFailure(hr, "failed to initialize"); // Open the Services Control Manager up front. hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (NULL == hSCM) { er = ::GetLastError(); hr = HRESULT_FROM_WIN32(er); #pragma prefast(push) #pragma prefast(disable:25028) ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); #pragma prefast(pop) ExitOnFailure1(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf); } // First, get the script key out of the CustomActionData and // use that to create the rollback script for this action. hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); if (!pwzScriptKey) { hr = E_UNEXPECTED; ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed."); } ExitOnFailure(hr, "Failed to read encoding key from CustomActionData."); hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); ExitOnFailure(hr, "Failed to open rollback CustomAction script."); // Next, loop through the rest of the CustomActionData, processing // each service config row in turn. while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&fNewService)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwResetPeriodInDays)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwRestartServiceDelayInSeconds)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); ExitOnFailure(hr, "failed to process CustomActionData"); WcaLog(LOGMSG_VERBOSE, "Configuring Service: %ls", pwzServiceName); // Open the handle with all the permissions we might need: // SERVICE_QUERY_CONFIG is needed for QueryServiceConfig2(). // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2(). // SERVICE_START is required in order to handle SC_ACTION_RESTART action. hr = GetService(hSCM, pwzServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_START, &hService); ExitOnFailure1(hr, "Failed to get service: %ls", pwzServiceName); // If we are configuring a service that existed on the machine, we need to // read the existing service configuration and write it out to the rollback // log so rollback can put it back if anything goes wrong. if (!fNewService) { // First, read the existing service config. if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &cbExistingServiceConfig) && ERROR_INSUFFICIENT_BUFFER != ::GetLastError()) { ExitWithLastError(hr, "Failed to get current service config info."); } psfa = static_cast<LPSERVICE_FAILURE_ACTIONSW>(MemAlloc(cbExistingServiceConfig, TRUE)); ExitOnNull(psfa, hr, E_OUTOFMEMORY, "failed to allocate memory for service failure actions."); if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)psfa, cbExistingServiceConfig, &cbExistingServiceConfig)) { ExitOnLastError(hr, "failed to Query Service."); } // Build up rollback log so we can restore service state if necessary hr = WcaCaScriptWriteString(hRollbackScript, pwzServiceName); ExitOnFailure(hr, "Failed to add service name to Rollback Log"); // If this service struct is empty, fill in default values if (3 > psfa->cActions) { hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); } else { // psfa actually had actions defined, so use the first three. for (int i = 0; i < 3; ++i) { hr = GetSCActionTypeString(psfa->lpsaActions[i].Type, wzActionName, countof(wzActionName)); ExitOnFailure(hr, "failed to query SFA object"); if (SC_ACTION_RESTART == psfa->lpsaActions[i].Type) { dwRestartDelay = psfa->lpsaActions[i].Delay / 1000; } hr = WcaCaScriptWriteString(hRollbackScript, wzActionName); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); } } hr = WcaCaScriptWriteNumber(hRollbackScript, psfa->dwResetPeriod / (24 * 60 * 60)); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaCaScriptWriteNumber(hRollbackScript, dwRestartDelay); ExitOnFailure(hr, "failed to add data to CustomActionData"); // Handle the null cases. if (!psfa->lpCommand) { psfa->lpCommand = L""; } hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpCommand); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); // Handle the null cases. if (!psfa->lpRebootMsg) { psfa->lpRebootMsg = L""; } hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpRebootMsg); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); // Nudge the system to get all our rollback data written to disk. WcaCaScriptFlush(hRollbackScript); ReleaseNullMem(psfa); } hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType, pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine); ExitOnFailure1(hr, "Failed to configure service: %ls", pwzServiceName); hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); ExitOnFailure(hr, "failed to send progress message"); // Per-service cleanup ::CloseServiceHandle(hService); hService = NULL; dwResetPeriodInDays = 0; dwRestartServiceDelayInSeconds = 0; } LExit: WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); if (lpMsgBuf) { ::LocalFree(lpMsgBuf); } if (hService) { ::CloseServiceHandle(hService); } if (hSCM) { ::CloseServiceHandle(hSCM); } ReleaseMem(psfa); ReleaseStr(pwzRebootMessage); ReleaseStr(pwzProgramCommandLine); ReleaseStr(pwzThirdFailureActionType); ReleaseStr(pwzSecondFailureActionType); ReleaseStr(pwzFirstFailureActionType); ReleaseStr(pwzServiceName); ReleaseStr(pwzScriptKey); ReleaseStr(pwzCustomActionData); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
UINT __stdcall ExecAddinRegistration(MSIHANDLE hInstall) { // AssertSz(FALSE, "debug ExecAddinRegistration"); LPWSTR pwzCustomActionData = NULL; LPWSTR pwzData = NULL; LPWSTR pwz = NULL; int iOperation = 0; LPWSTR pwzId = NULL; LPWSTR pwzFile = NULL; LPWSTR pwzName = NULL; LPWSTR pwzDescription = NULL; int iBitness = REG_KEY_DEFAULT; int iCommandLineSafe = 1; int iLoadBehavior = 3; LPWSTR pwzAllUsers = NULL; HRESULT hr = WcaInitialize(hInstall, "ExecAddinRegistration"); ExitOnFailure(hr, "Failed to initialize"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = RegInitialize(); ExitOnFailure(hr, "Failed to initialize the registry functions."); // loop through all the passed in data while (pwz && *pwz) { // extract the custom action data hr = WcaReadIntegerFromCaData(&pwz, &iOperation); ExitOnFailure(hr, "failed to read operation from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzId); ExitOnFailure(hr, "failed to read id from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzFile); ExitOnFailure(hr, "failed to read path from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to read name from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzDescription); ExitOnFailure(hr, "failed to read description from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iBitness); ExitOnFailure(hr, "failed to read bitness from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iCommandLineSafe); ExitOnFailure(hr, "failed to read CommandLineSafe from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iLoadBehavior); ExitOnFailure(hr, "failed to read LoadBehavior from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzAllUsers); ExitOnFailure(hr, "failed to read ALLUSERS from custom action data"); BOOL fPerUserInstall = (!pwzAllUsers || !*pwzAllUsers); // if rolling back, swap INSTALL and UNINSTALL if (::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK)) { if (WCA_TODO_INSTALL == iOperation) { iOperation = WCA_TODO_UNINSTALL; } else if (WCA_TODO_UNINSTALL == iOperation) { iOperation = WCA_TODO_INSTALL; } } switch (iOperation) { case WCA_TODO_INSTALL: case WCA_TODO_REINSTALL: hr = CreateOfficeRegistryKey(pwzId, pwzFile, pwzName, pwzDescription, iCommandLineSafe, iLoadBehavior, fPerUserInstall, iBitness); ExitOnFailure1(hr, "failed to register addin %ls", pwzId); break; case WCA_TODO_UNINSTALL: hr = DeleteOfficeRegistryKey(pwzId, fPerUserInstall, iBitness); ExitOnFailure1(hr, "failed to unregister addin %ls", pwzId); break; } // Tick the progress bar along for this addin hr = WcaProgressMessage(COST_REGISTER_ADDIN, FALSE); ExitOnFailure1(hr, "failed to tick progress bar for addin registration: %ls", pwzId); } LExit: RegUninitialize(); ReleaseStr(pwzAllUsers); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzId); ReleaseStr(pwzFile); ReleaseStr(pwzName); ReleaseStr(pwzDescription); return WcaFinalize(SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE); }
/****************************************************************** RollbackServiceConfig - entry point for ServiceConfig rollback Custom Action. NOTE: CustomActionScript Data == wzServiceName\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\t... *******************************************************************/ extern "C" UINT __stdcall RollbackServiceConfig( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug RollbackServiceConfig"); HRESULT hr = S_OK; DWORD er = 0; LPWSTR pwzCustomActionData = NULL; LPWSTR pwz = NULL; LPWSTR pwzScriptKey = NULL; WCA_CASCRIPT_HANDLE hRollbackScript = NULL; LPWSTR pwzServiceName = NULL; LPWSTR pwzFirstFailureActionType = NULL; LPWSTR pwzSecondFailureActionType = NULL; LPWSTR pwzThirdFailureActionType = NULL; LPWSTR pwzProgramCommandLine = NULL; LPWSTR pwzRebootMessage = NULL; DWORD dwResetPeriodInDays = 0; DWORD dwRestartServiceDelayInSeconds = 0; LPVOID lpMsgBuf = NULL; SC_HANDLE hSCM = NULL; SC_HANDLE hService = NULL; // initialize hr = WcaInitialize(hInstall, "RollbackServiceConfig"); ExitOnFailure(hr, "Failed to initialize 'RollbackServiceConfig'."); // Open the Services Control Manager up front. hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (NULL == hSCM) { er = ::GetLastError(); hr = HRESULT_FROM_WIN32(er); #pragma prefast(push) #pragma prefast(disable:25028) ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); #pragma prefast(pop) ExitOnFailure1(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf); // Make sure we still abort, in case hSCM was NULL but no error was returned from GetLastError ExitOnNull(hSCM, hr, E_POINTER, "Getting handle to SCM reported success, but no handle was returned."); } // Get the script key from the CustomAction data and use it to open // the rollback log and read the data over the CustomActionData // because all of the information is in the script data not the // CustomActionData. hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); if (!pwzScriptKey) { hr = E_UNEXPECTED; ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed."); } ExitOnFailure(hr, "Failed to read encoding key from CustomActionData."); hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); ExitOnFailure(hr, "Failed to open rollback CustomAction script."); hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzCustomActionData); ExitOnFailure(hr, "Failed to read rollback script into CustomAction data."); // Loop through the script's CustomActionData, processing each // service config in turn. pwz = pwzCustomActionData; while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwResetPeriodInDays)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwRestartServiceDelayInSeconds)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); ExitOnFailure(hr, "failed to process CustomActionData"); WcaLog(LOGMSG_VERBOSE, "Reconfiguring Service: %ls", pwzServiceName); // Open the handle with all the permissions we might need. // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2(). // SERVICE_START is required in order to handle SC_ACTION_RESTART action. hr = GetService(hSCM, pwzServiceName, SERVICE_CHANGE_CONFIG | SERVICE_START, &hService); ExitOnFailure1(hr, "Failed to get service: %ls", pwzServiceName); hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType, pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine); ExitOnFailure1(hr, "Failed to configure service: %ls", pwzServiceName); hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); ExitOnFailure(hr, "failed to send progress message"); // Per-service cleanup ::CloseServiceHandle(hService); hService = NULL; dwResetPeriodInDays = 0; dwRestartServiceDelayInSeconds = 0; } LExit: if (lpMsgBuf) // Allocated with FormatString. { ::LocalFree(lpMsgBuf); } if (hService) { ::CloseServiceHandle(hService); } if (hSCM) { ::CloseServiceHandle(hSCM); } WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); ReleaseStr(pwzRebootMessage); ReleaseStr(pwzProgramCommandLine); ReleaseStr(pwzThirdFailureActionType); ReleaseStr(pwzSecondFailureActionType); ReleaseStr(pwzFirstFailureActionType); ReleaseStr(pwzServiceName); ReleaseStr(pwzScriptKey); ReleaseStr(pwzCustomActionData); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** CaExecSecureObjects - entry point for SecureObjects Custom Action called as Type 1025 CustomAction (deferred binary DLL) NOTE: deferred CustomAction since it modifies the machine NOTE: CustomActionData == wzObject\twzTable\twzDomain\twzUser\tdwPermissions\twzObject\t... ******************************************************************/ extern "C" UINT __stdcall ExecSecureObjects( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug ExecSecureObjects"); HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; LPWSTR pwz = NULL; LPWSTR pwzData = NULL; LPWSTR pwzObject = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzDomain = NULL; DWORD dwRevision = 0; LPWSTR pwzUser = NULL; DWORD dwPermissions = 0; LPWSTR pwzAccount = NULL; PSID psid = NULL; EXPLICIT_ACCESSW ea = {0}; SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; PSECURITY_DESCRIPTOR psd = NULL; SECURITY_DESCRIPTOR_CONTROL sdc = {0}; SECURITY_INFORMATION si = {0}; PACL pAclExisting = NULL; // doesn't get freed PACL pAclNew = NULL; PMSIHANDLE hActionRec = ::MsiCreateRecord(1); // // initialize // hr = WcaInitialize(hInstall, "ExecSecureObjects"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty(L"CustomActionData", &pwzData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %S", pwzData); pwz = pwzData; // // loop through all the passed in data // while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzObject); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzTable); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzDomain); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzUser); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwPermissions)); ExitOnFailure(hr, "failed to processCustomActionData"); WcaLog(LOGMSG_VERBOSE, "Securing Object: %S Type: %S User: %S", pwzObject, pwzTable, pwzUser); // // create the appropriate SID // // figure out the right user to put into the access block if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Everyone")) { hr = AclGetWellKnownSid(WinWorldSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Administrators")) { hr = AclGetWellKnownSid(WinBuiltinAdministratorsSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalSystem")) { hr = AclGetWellKnownSid(WinLocalSystemSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalService")) { hr = AclGetWellKnownSid(WinLocalServiceSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"NetworkService")) { hr = AclGetWellKnownSid(WinNetworkServiceSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"AuthenticatedUser")) { hr = AclGetWellKnownSid(WinAuthenticatedUserSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Guests")) { hr = AclGetWellKnownSid(WinBuiltinGuestsSid, &psid); } else if(!*pwzDomain && 0 == lstrcmpW(pwzUser, L"CREATOR OWNER")) { hr = AclGetWellKnownSid(WinCreatorOwnerSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"INTERACTIVE")) { hr = AclGetWellKnownSid(WinInteractiveSid, &psid); } else if(!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Users")) { hr = AclGetWellKnownSid(WinBuiltinUsersSid, &psid); } else { hr = StrAllocFormatted(&pwzAccount, L"%s\\%s", *pwzDomain ? pwzDomain : L".", pwzUser); ExitOnFailure(hr, "failed to build domain user name"); hr = AclGetAccountSid(NULL, pwzAccount, &psid); } ExitOnFailure3(hr, "failed to get sid for account: %S%S%S", pwzDomain, *pwzDomain ? L"\\" : L"", pwzUser); // // build up the explicit access // ea.grfAccessPermissions = dwPermissions; ea.grfAccessMode = SET_ACCESS; if (0 == lstrcmpW(L"CreateFolder", pwzTable)) { ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; } else { ea.grfInheritance = NO_INHERITANCE; } ::BuildTrusteeWithSidW(&ea.Trustee, psid); if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) { objectType = SE_SERVICE; // always add these permissions for services // these are basic permissions that are often forgotten dwPermissions |= SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_INTERROGATE; } else if (0 == lstrcmpW(L"CreateFolder", pwzTable) || 0 == lstrcmpW(L"File", pwzTable)) { objectType = SE_FILE_OBJECT; } else if (0 == lstrcmpW(L"Registry", pwzTable)) { objectType = SE_REGISTRY_KEY; } if (SE_UNKNOWN_OBJECT_TYPE != objectType) { er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pAclExisting, NULL, &psd); ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get security info for object: %S", pwzObject); //Need to see if DACL is protected so getting Descriptor information if(!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) { ExitOnLastError1(hr, "failed to get security descriptor control for object: %S", pwzObject); } er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclNew); ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to add ACLs for object: %S", pwzObject); if (sdc & SE_DACL_PROTECTED) { si = DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION; } else { si = DACL_SECURITY_INFORMATION; } er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pAclNew, NULL); MessageExitOnFailure1(hr = HRESULT_FROM_WIN32(er), msierrSecureObjectsFailedSet, "failed to set security info for object: %S", pwzObject); } else { MessageExitOnFailure1(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %S", pwzTable); } hr = WcaProgressMessage(COST_SECUREOBJECT, FALSE); ExitOnFailure(hr, "failed to send progress message"); objectType = SE_UNKNOWN_OBJECT_TYPE; } LExit: ReleaseStr(pwzUser); ReleaseStr(pwzDomain); ReleaseStr(pwzTable); ReleaseStr(pwzObject); ReleaseStr(pwzData); ReleaseStr(pwzAccount); if (pAclNew) ::LocalFree(pAclNew); if (psd) ::LocalFree(psd); if (psid) AclFreeSid(psid); if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** CaExecServiceConfig - entry point for ServiceConfig Custom Action called as Type 1025 CustomAction (deferred binary DLL) NOTE: deferred CustomAction since it modifies the machine NOTE: CustomActionData == wzServiceName\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\t... *******************************************************************/ extern "C" UINT __stdcall ExecServiceConfig( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug ExecServiceConfig"); HRESULT hr = S_OK; UINT uiResult = ERROR_SUCCESS; DWORD dwError = 0; LPVOID lpMsgBuf = NULL; LPWSTR pwzData = NULL; LPWSTR pwz = NULL; LPWSTR pwzServiceName = NULL; LPWSTR pwzFirstFailureActionType = NULL; LPWSTR pwzSecondFailureActionType = NULL; LPWSTR pwzThirdFailureActionType = NULL; LPWSTR pwzProgramCommandLine = NULL; LPWSTR pwzRebootMessage = NULL; DWORD dwResetPeriodInDays = 0; DWORD dwRestartServiceDelayInSeconds = 0; SC_HANDLE hSCM = NULL; SC_HANDLE hService = NULL; DWORD dwOpenServiceAccess = SERVICE_CHANGE_CONFIG; // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2() SERVICE_FAILURE_ACTIONSW sfa; SC_ACTION actions[3]; BOOL fResult = FALSE; // initialize hr = WcaInitialize(hInstall, "ExecServiceConfig"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty( L"CustomActionData", &pwzData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %S", pwzData); pwz = pwzData; // loop through all the passed in data while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwResetPeriodInDays)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwRestartServiceDelayInSeconds)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); ExitOnFailure(hr, "failed to process CustomActionData"); WcaLog(LOGMSG_VERBOSE, "Configuring Service: %S", pwzServiceName); // build up SC_ACTION array // TODO: why is delay only respected when SC_ACTION_RESTART is requested? actions[0].Type = GetSCActionType(pwzFirstFailureActionType); actions[0].Delay = 0; if (SC_ACTION_RESTART == actions[0].Type) { actions[0].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds dwOpenServiceAccess |= SERVICE_START; // must have SERVICE_START access in order to handle SC_ACTION_RESTART action; } actions[1].Type = GetSCActionType(pwzSecondFailureActionType); actions[1].Delay = 0; if (SC_ACTION_RESTART == actions[1].Type) { actions[1].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds dwOpenServiceAccess |= SERVICE_START; // must have SERVICE_START access in order to handle SC_ACTION_RESTART action; } actions[2].Type = GetSCActionType(pwzThirdFailureActionType); actions[2].Delay = 0; if (SC_ACTION_RESTART == actions[2].Type) { actions[2].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds dwOpenServiceAccess |= SERVICE_START; // must have SERVICE_START access in order to handle SC_ACTION_RESTART action; } // build up the SERVICE_FAILURE_ACTIONSW struct sfa.dwResetPeriod = dwResetPeriodInDays * 24 * 60 * 60; // days to seconds sfa.lpRebootMsg = pwzRebootMessage; sfa.lpCommand = pwzProgramCommandLine; sfa.cActions = 3; // the UI always shows 3 actions, so we'll always do 3 sfa.lpsaActions = actions; // Get a handle to the service control manager (if we don't already have) if (NULL == hSCM) { hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (hSCM == NULL) { dwError = ::GetLastError(); ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); ExitOnFailure1(hr = HRESULT_FROM_WIN32(dwError), "failed to get handle to SCM. Error: %S", (LPWSTR)lpMsgBuf); } } hService = ::OpenServiceW(hSCM, pwzServiceName, dwOpenServiceAccess); if (hService == NULL) { dwError = ::GetLastError(); hr = HRESULT_FROM_WIN32(dwError); if (dwError == ERROR_SERVICE_DOES_NOT_EXIST) { ExitOnFailure1(hr, "Service \"%S\" does not exist on this system.", pwzServiceName); } else { ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); ExitOnFailure2(hr, "Failed to get handle to the service \"%S\". Error: %S", pwzServiceName, (LPWSTR)lpMsgBuf); } } // Call ChangeServiceConfig2 to actually set up the failure actions fResult = ChangeServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPVOID)&sfa); if (fResult == FALSE) { dwError = ::GetLastError(); hr = HRESULT_FROM_WIN32(dwError); ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); // check if this is a service that can't be modified if(dwError == ERROR_CANNOT_DETECT_PROCESS_ABORT) { WcaLog(LOGMSG_STANDARD, "WARNING: Service \"%S\" is not configurable on this server and will not be set.", pwzServiceName); } ExitOnFailure1(hr, "Cannot change service configuration. Error: %S", (LPWSTR)lpMsgBuf); } // Per-service cleanup dwResetPeriodInDays = 0; dwRestartServiceDelayInSeconds = 0; hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); ExitOnFailure(hr, "failed to send progress message"); } LExit: // Clean up handles ReleaseStr(pwzServiceName); ReleaseStr(pwzFirstFailureActionType); ReleaseStr(pwzSecondFailureActionType); ReleaseStr(pwzThirdFailureActionType); ReleaseStr(pwzProgramCommandLine); ReleaseStr(pwzRebootMessage); ReleaseStr(pwzData); if (lpMsgBuf) // Allocated with FormatString ::LocalFree(lpMsgBuf); if (hService) ::CloseServiceHandle(hService); if (hSCM) ::CloseServiceHandle(hSCM); if (FAILED(hr)) uiResult = ERROR_INSTALL_FAILURE; return WcaFinalize(uiResult); }
/****************************************************************** ExecFirewallExceptions - deferred custom action entry point to register and remove firewall exceptions. ********************************************************************/ extern "C" UINT __stdcall ExecFirewallExceptions( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; BOOL fSupportProfiles = FALSE; LPWSTR pwz = NULL; LPWSTR pwzCustomActionData = NULL; int iTodo = WCA_TODO_UNKNOWN; LPWSTR pwzName = NULL; LPWSTR pwzRemoteAddresses = NULL; int iAttributes = 0; int iTarget = fetUnknown; LPWSTR pwzFile = NULL; LPWSTR pwzPort = NULL; LPWSTR pwzDescription = NULL; int iProtocol = 0; int iProfile = 0; // initialize hr = WcaInitialize(hInstall, "ExecFirewallExceptions"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to initialize COM"); // Find out if we support profiles (only on Vista or later) fSupportProfiles = FSupportProfiles(); // loop through all the passed in data pwz = pwzCustomActionData; while (pwz && *pwz) { // extract the custom action data and if rolling back, swap INSTALL and UNINSTALL hr = WcaReadIntegerFromCaData(&pwz, &iTodo); ExitOnFailure(hr, "failed to read todo from custom action data"); if (::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK)) { if (WCA_TODO_INSTALL == iTodo) { iTodo = WCA_TODO_UNINSTALL; } else if (WCA_TODO_UNINSTALL == iTodo) { iTodo = WCA_TODO_INSTALL; } } hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to read name from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iProfile); ExitOnFailure(hr, "failed to read profile from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzRemoteAddresses); ExitOnFailure(hr, "failed to read remote addresses from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); ExitOnFailure(hr, "failed to read attributes from custom action data"); BOOL fIgnoreFailures = feaIgnoreFailures == (iAttributes & feaIgnoreFailures); hr = WcaReadIntegerFromCaData(&pwz, &iTarget); ExitOnFailure(hr, "failed to read target from custom action data"); if (iTarget == fetApplication) { hr = WcaReadStringFromCaData(&pwz, &pwzFile); ExitOnFailure(hr, "failed to read file path from custom action data"); } hr = WcaReadStringFromCaData(&pwz, &pwzPort); ExitOnFailure(hr, "failed to read port from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iProtocol); ExitOnFailure(hr, "failed to read protocol from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzDescription); ExitOnFailure(hr, "failed to read protocol from custom action data"); switch (iTarget) { case fetPort: switch (iTodo) { case WCA_TODO_INSTALL: case WCA_TODO_REINSTALL: WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); hr = AddPortException(fSupportProfiles, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription); ExitOnFailure3(hr, "failed to add/update port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); break; case WCA_TODO_UNINSTALL: WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); hr = RemovePortException(fSupportProfiles, pwzName, pwzPort, iProtocol, fIgnoreFailures); ExitOnFailure3(hr, "failed to remove port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); break; } break; case fetApplication: switch (iTodo) { case WCA_TODO_INSTALL: case WCA_TODO_REINSTALL: WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls (%ls)", pwzName, pwzFile); hr = AddApplicationException(fSupportProfiles, pwzFile, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription); ExitOnFailure2(hr, "failed to add/update application exception for name '%ls', file '%ls'", pwzName, pwzFile); break; case WCA_TODO_UNINSTALL: WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls (%ls)", pwzName, pwzFile); hr = RemoveApplicationException(fSupportProfiles, pwzName, pwzFile, fIgnoreFailures, pwzPort, iProtocol); ExitOnFailure2(hr, "failed to remove application exception for name '%ls', file '%ls'", pwzName, pwzFile); break; } break; } } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzName); ReleaseStr(pwzRemoteAddresses); ReleaseStr(pwzFile); ReleaseStr(pwzPort); ReleaseStr(pwzDescription); ::CoUninitialize(); return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS); }
/******************************************************************** ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings ********************************************************************/ extern "C" UINT __stdcall ConfigureIIs7Exec( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ConfigureIIs7Exec here"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzScriptKey = NULL; LPWSTR pwzCustomActionData = NULL; SCA_WEB7* pswList = NULL; SCA_WEBDIR7* pswdList = NULL; SCA_VDIR7* psvdList = NULL; SCA_FILTER* psfList = NULL; SCA_APPPOOL *psapList = NULL; SCA_MIMEMAP* psmmList = NULL; SCA_HTTP_HEADER* pshhList = NULL; SCA_PROPERTY *pspList = NULL; SCA_WEBSVCEXT* psWseList = NULL; SCA_WEB_ERROR* psweList = NULL; WCA_WRAPQUERY_HANDLE hUserQuery = NULL; WCA_WRAPQUERY_HANDLE hWebBaseQuery = NULL; WCA_WRAPQUERY_HANDLE hWebDirPropQuery = NULL; WCA_WRAPQUERY_HANDLE hSslCertQuery = NULL; WCA_WRAPQUERY_HANDLE hWebLogQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppExtQuery = NULL; // initialize hr = WcaInitialize(hInstall, "ConfigureIIs7Exec"); ExitOnFailure(hr, "Failed to initialize"); hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); // Get the CaScript key hr = WcaReadStringFromCaData(&pwzCustomActionData, &pwzScriptKey); ExitOnFailure(hr, "Failed to get CaScript key from custom action data"); // read the msi tables hr = WcaBeginUnwrapQuery(&hUserQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap user query"); hr = ScaWebSvcExtRead(&psWseList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSvcExt, "failed while processing WebServiceExtensions"); hr = ScaAppPoolRead(&psapList, hUserQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadAppPool, "failed while processing WebAppPools"); // MimeMap, Error and HttpHeader need to be read before the virtual directory and web read hr = ScaMimeMapRead(&psmmList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadMimeMap, "failed while processing MimeMaps"); hr = ScaHttpHeaderRead(&pshhList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadHttpHeader, "failed while processing HttpHeaders"); hr = ScaWebErrorRead(&psweList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebError, "failed while processing WebErrors"); hr = WcaBeginUnwrapQuery(&hWebDirPropQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web dir properties query"); hr = WcaBeginUnwrapQuery(&hSslCertQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap ssl certificate query"); hr = WcaBeginUnwrapQuery(&hWebLogQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web log query"); hr = WcaBeginUnwrapQuery(&hWebAppQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application query"); hr = WcaBeginUnwrapQuery(&hWebAppExtQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application extension query"); hr = ScaWebsRead7(&pswList, &pshhList, &psweList, hUserQuery, hWebDirPropQuery, hSslCertQuery, hWebLogQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSite, "failed while processing WebSites"); hr = WcaBeginUnwrapQuery(&hWebBaseQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web base query"); hr = ScaWebDirsRead7(pswList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData, &pswdList); MessageExitOnFailure(hr, msierrIISFailedReadWebDirs, "failed while processing WebDirs"); hr = ScaVirtualDirsRead7(pswList, &psvdList, &psmmList, &pshhList, &psweList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadVDirs, "failed while processing WebVirtualDirs"); hr = ScaFiltersRead7(pswList, hWebBaseQuery, &psfList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadFilters, "failed while processing WebFilters"); hr = ScaPropertyRead(&pspList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadProp, "failed while processing WebProperties"); // do uninstall actions (order is important!) hr = ScaPropertyUninstall7(pspList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallProp, "failed to uninstall IIS properties"); hr = ScaFiltersUninstall7(psfList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallFilters, "failed to schedule uninstall of filters"); hr = ScaVirtualDirsUninstall7(psvdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallVDirs, "failed to schedule uninstall of virtual directories"); hr = ScaWebDirsUninstall7(pswdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebDirs, "failed to schedule uninstall of web directories"); hr = ScaWebsUninstall7(pswList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebs, "failed to schedule uninstall of webs"); hr = ScaAppPoolUninstall7(psapList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallAppPool, "failed to schedule uninstall of AppPools"); // do install actions (order is important!) // ScaWebSvcExtCommit contains both uninstall and install actions. hr = ScaWebSvcExtCommit7(psWseList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebSvcExt, "failed to schedule install/uninstall of WebSvcExt"); hr = ScaAppPoolInstall7(psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallAppPool, "failed to schedule install of AppPools"); hr = ScaWebsInstall7(pswList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebs, "failed to schedule install of webs"); hr = ScaWebDirsInstall7(pswdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebDirs, "failed to schedule install of web directories"); hr = ScaVirtualDirsInstall7(psvdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallVDirs, "failed to schedule install of virtual directories"); hr = ScaFiltersInstall7(psfList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallFilters, "failed to schedule install of filters"); hr = ScaPropertyInstall7(pspList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallProp, "failed to schedule install of properties"); hr = ScaWriteConfigurationScript(pwzScriptKey); ExitOnFailure(hr, "failed to schedule metabase configuration"); LExit: ReleaseNullStr(pwzScriptKey); ReleaseNullStr(pwzCustomActionData); WcaFinishUnwrapQuery(hUserQuery); WcaFinishUnwrapQuery(hWebBaseQuery); WcaFinishUnwrapQuery(hWebDirPropQuery); WcaFinishUnwrapQuery(hSslCertQuery); WcaFinishUnwrapQuery(hWebLogQuery); WcaFinishUnwrapQuery(hWebAppQuery); WcaFinishUnwrapQuery(hWebAppExtQuery); if (psWseList) { ScaWebSvcExtFreeList(psWseList); } if (psfList) { ScaFiltersFreeList(psfList); } if (psvdList) { ScaVirtualDirsFreeList7(psvdList); } if (pswdList) { ScaWebDirsFreeList7(pswdList); } if (pswList) { ScaWebsFreeList7(pswList); } if (psmmList) { ScaMimeMapFreeList(psmmList); } if (pshhList) { ScaHttpHeaderCheckList(pshhList); ScaHttpHeaderFreeList(pshhList); } if (psweList) { ScaWebErrorCheckList(psweList); ScaWebErrorFreeList(psweList); } er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** ExecXmlConfig - entry point for XmlConfig Custom Action *******************************************************************/ extern "C" UINT __stdcall ExecXmlConfig( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ExecXmlConfig"); HRESULT hr = S_OK; HRESULT hrOpenFailure = S_OK; UINT er = ERROR_SUCCESS; BOOL fIsWow64Process = FALSE; BOOL fIsFSRedirectDisabled = FALSE; BOOL fPreserveDate = FALSE; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzData = NULL; LPWSTR pwzFile = NULL; LPWSTR pwzElementPath = NULL; LPWSTR pwzVerifyPath = NULL; LPWSTR pwzName = NULL; LPWSTR pwzValue = NULL; LPWSTR pwz = NULL; int cAdditionalChanges = 0; IXMLDOMDocument* pixd = NULL; IXMLDOMNode* pixn = NULL; IXMLDOMNode* pixnVerify = NULL; IXMLDOMNode* pixnNewNode = NULL; IXMLDOMNode* pixnRemovedChild = NULL; IXMLDOMDocument* pixdNew = NULL; IXMLDOMElement* pixeNew = NULL; FILETIME ft; int id = IDRETRY; eXmlAction xa; eXmlPreserveDate xd; // initialize hr = WcaInitialize(hInstall, "ExecXmlConfig"); ExitOnFailure(hr, "failed to initialize"); hr = XmlInitialize(); ExitOnFailure(hr, "failed to initialize xml utilities"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); ExitOnFailure(hr, "failed to process CustomActionData"); // Initialize the Wow64 API - store the result in fWow64APIPresent // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases WcaInitializeWow64(); fIsWow64Process = WcaIsWow64Process(); if (xaOpenFile != xa && xaOpenFilex64 != xa) { ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data"); } // loop through all the passed in data while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzFile); ExitOnFailure(hr, "failed to read file name from custom action data"); // Default to not preserve date, preserve it if any modifications require us to fPreserveDate = FALSE; // Open the file ReleaseNullObject(pixd); if (xaOpenFilex64 == xa) { if (!fIsWow64Process) { hr = E_NOTIMPL; ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW."); } hr = WcaDisableWow64FSRedirection(); ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); fIsFSRedirectDisabled = TRUE; } hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd); if (FAILED(hr)) { // Ignore the return code for now. If they try to add something, we'll fail the install. If all they do is remove stuff then it doesn't matter. hrOpenFailure = hr; hr = S_OK; } else { hrOpenFailure = S_OK; } WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile); while (pwz && *pwz) { // If we skip past an element that has additional changes we need to strip them off the stream before // moving on to the next element. Do that now and then restart the outer loop. if (cAdditionalChanges > 0) { while (cAdditionalChanges > 0) { hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); cAdditionalChanges--; } continue; } hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); ExitOnFailure(hr, "failed to process CustomActionData"); // Break if we need to move on to a different file if (xaOpenFile == xa || xaOpenFilex64 == xa) { break; } hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd); ExitOnFailure(hr, "failed to process CustomActionData"); if (xdPreserve == xd) { fPreserveDate = TRUE; } // Get path, name, and value to be written hr = WcaReadStringFromCaData(&pwz, &pwzElementPath); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzVerifyPath); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, &cAdditionalChanges); ExitOnFailure(hr, "failed to process CustomActionData"); // If we failed to open the file and we're adding something to the file, we've got a problem. Otherwise, just continue on since the file's already gone. if (FAILED(hrOpenFailure)) { if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) { MessageExitOnFailure1(hr = hrOpenFailure, msierrXmlConfigFailedOpen, "failed to load XML file: %ls", pwzFile); } else { continue; } } // Select the node we're about to modify ReleaseNullObject(pixn); hr = XmlSelectSingleNode(pixd, pwzElementPath, &pixn); // If we failed to find the node that we are going to add to, we've got a problem. Otherwise, just continue since the node's already gone. if (S_FALSE == hr) { if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) { hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); } else { hr = S_OK; continue; } } MessageExitOnFailure2(hr, msierrXmlConfigFailedSelect, "failed to find node: %ls in XML file: %ls", pwzElementPath, pwzFile); // Make the modification switch (xa) { case xaWriteValue: if (pwzName && *pwzName) { // We're setting an attribute hr = XmlSetAttribute(pixn, pwzName, pwzValue); ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); } else { // We're setting the text of the node hr = XmlSetText(pixn, pwzValue); ExitOnFailure2(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzElementPath); } break; case xaWriteDocument: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { // We found the verify path which means we have no further work to do continue; } ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath); } hr = XmlLoadDocumentEx(pwzValue, XML_LOAD_PRESERVE_WHITESPACE, &pixdNew); ExitOnFailure(hr, "Failed to load value as document."); hr = pixdNew->get_documentElement(&pixeNew); ExitOnFailure(hr, "Failed to get document element."); hr = pixn->appendChild(pixeNew, NULL); ExitOnFailure(hr, "Failed to append document element on to parent element."); ReleaseNullObject(pixeNew); ReleaseNullObject(pixdNew); break; case xaCreateElement: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { // We found the verify path which means we have no further work to do continue; } ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath); } hr = XmlCreateChild(pixn, pwzName, &pixnNewNode); ExitOnFailure1(hr, "failed to create child element: %ls", pwzName); if (pwzValue && *pwzValue) { hr = XmlSetText(pixnNewNode, pwzValue); ExitOnFailure2(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName); } while (cAdditionalChanges > 0) { hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); // Set the additional attribute hr = XmlSetAttribute(pixnNewNode, pwzName, pwzValue); ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); cAdditionalChanges--; } ReleaseNullObject(pixnNewNode); break; case xaDeleteValue: if (pwzName && *pwzName) { // Delete the attribute hr = XmlRemoveAttribute(pixn, pwzName); ExitOnFailure1(hr, "failed to remove attribute: %ls", pwzName); } else { // Clear the text value for the node hr = XmlSetText(pixn, L""); ExitOnFailure(hr, "failed to clear text value"); } break; case xaDeleteElement: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { hr = pixn->removeChild(pixnVerify, &pixnRemovedChild); ExitOnFailure(hr, "failed to remove created child element"); ReleaseNullObject(pixnRemovedChild); } else { WcaLog(LOGMSG_VERBOSE, "Failed to select path %ls for deleting. Skipping...", pwzVerifyPath); hr = S_OK; } } else { // TODO: This requires a VerifyPath to delete an element. Should we support not having one? WcaLog(LOGMSG_VERBOSE, "No VerifyPath specified for delete element of ID: %ls", pwzElementPath); } break; default: ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data"); break; } } // Now that we've made all of the changes to this file, save it and move on to the next if (S_OK == hrOpenFailure) { if (fPreserveDate) { hr = FileGetTime(pwzFile, NULL, NULL, &ft); ExitOnFailure1(hr, "failed to get modified time of file : %ls", pwzFile); } int iSaveAttempt = 0; do { hr = XmlSaveDocument(pixd, pwzFile); if (FAILED(hr)) { id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile); switch (id) { case IDABORT: ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); case IDRETRY: hr = S_FALSE; // hit me, baby, one more time break; case IDIGNORE: hr = S_OK; // pretend everything is okay and bail break; case 0: // No UI case, MsiProcessMessage returns 0 if (STIERR_SHARING_VIOLATION == hr) { // Only in case of sharing violation do we retry 30 times, once a second. if (iSaveAttempt < 30) { hr = S_FALSE; ++iSaveAttempt; WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt); Sleep(1000); } else { ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); } } break; default: // Unknown error ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); } } } while (S_FALSE == hr); if (fPreserveDate) { hr = FileSetTime(pwzFile, NULL, NULL, &ft); ExitOnFailure1(hr, "failed to set modified time of file : %ls", pwzFile); } if (fIsFSRedirectDisabled) { fIsFSRedirectDisabled = FALSE; WcaRevertWow64FSRedirection(); } } } LExit: // Make sure we revert FS Redirection if necessary before exiting if (fIsFSRedirectDisabled) { fIsFSRedirectDisabled = FALSE; WcaRevertWow64FSRedirection(); } WcaFinalizeWow64(); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzFile); ReleaseStr(pwzElementPath); ReleaseStr(pwzVerifyPath); ReleaseStr(pwzName); ReleaseStr(pwzValue); ReleaseObject(pixeNew); ReleaseObject(pixdNew); ReleaseObject(pixn); ReleaseObject(pixd); ReleaseObject(pixnNewNode); ReleaseObject(pixnRemovedChild); XmlUninitialize(); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/****************************************************************** ExecXmlConfigRollback - entry point for XmlConfig rollback Custom Action *******************************************************************/ extern "C" UINT __stdcall ExecXmlConfigRollback( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug ExecXmlConfigRollback"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; int iIs64Bit; BOOL fIs64Bit = FALSE; LPWSTR pwzCustomActionData = NULL; LPWSTR pwz = NULL; LPWSTR pwzFileName = NULL; LPBYTE pbData = NULL; DWORD_PTR cbData = 0; DWORD cbDataWritten = 0; FILETIME ft; HANDLE hFile = INVALID_HANDLE_VALUE; // initialize hr = WcaInitialize(hInstall, "ExecXmlConfigRollback"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadIntegerFromCaData(&pwz, &iIs64Bit); ExitOnFailure(hr, "failed to read component bitness from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzFileName); ExitOnFailure(hr, "failed to read file name from custom action data"); hr = WcaReadStreamFromCaData(&pwz, &pbData, &cbData); ExitOnFailure(hr, "failed to read file contents from custom action data"); fIs64Bit = (BOOL)iIs64Bit; if (fIs64Bit) { hr = WcaInitializeWow64(); if (S_FALSE == hr) { hr = TYPE_E_DLLFUNCTIONNOTFOUND; } ExitOnFailure(hr, "failed to initialize Wow64 API"); if (!WcaIsWow64Process()) { hr = E_NOTIMPL; ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but the Wow64 API is unavailable."); } hr = WcaDisableWow64FSRedirection(); ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but was unable to Disable Filesystem Redirection through the Wow64 API."); } hr = FileGetTime(pwzFileName, NULL, NULL, &ft); ExitOnFailure1(hr, "Failed to get modified date of file %ls.", pwzFileName); // Open the file hFile = ::CreateFileW(pwzFileName, GENERIC_WRITE, NULL, NULL, TRUNCATE_EXISTING, NULL, NULL); ExitOnInvalidHandleWithLastError1(hFile, hr, "failed to open file: %ls", pwzFileName); // Write out the old data if (!::WriteFile(hFile, pbData, (DWORD)cbData, &cbDataWritten, NULL)) { ExitOnLastError1(hr, "failed to write to file: %ls", pwzFileName); } Assert(cbData == cbDataWritten); ReleaseFile(hFile); hr = FileSetTime(pwzFileName, NULL, NULL, &ft); ExitOnFailure1(hr, "Failed to set modified date of file %ls.", pwzFileName); LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzFileName); ReleaseFile(hFile); if (fIs64Bit) { WcaRevertWow64FSRedirection(); WcaFinalizeWow64(); } ReleaseMem(pbData); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
static HRESULT ExecuteCertificateOperation( __in MSIHANDLE hInstall, __in SCA_ACTION saAction, __in DWORD dwStoreLocation ) { //AssertSz(FALSE, "Debug ExecuteCertificateOperation() here."); Assert(saAction & SCA_ACTION_INSTALL || saAction & SCA_ACTION_UNINSTALL); HRESULT hr = S_OK; LPWSTR pwzCaData = NULL; LPWSTR pwz; LPWSTR pwzName = NULL; LPWSTR pwzStore = NULL; int iAttributes = 0; LPWSTR pwzPFXPassword = NULL; LPWSTR pwzFilePath = NULL; BYTE* pbData = NULL; DWORD cbData = 0; DWORD cbPFXPassword = 0; BOOL fUserStoreLocation = (CERT_SYSTEM_STORE_CURRENT_USER == dwStoreLocation); HCERTSTORE hCertStore = NULL; hr = WcaGetProperty(L"CustomActionData", &pwzCaData); ExitOnFailure(hr, "Failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCaData); pwz = pwzCaData; hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "Failed to parse certificate name."); hr = WcaReadStringFromCaData(&pwz, &pwzStore); ExitOnFailure(hr, "Failed to parse CustomActionData, StoreName"); hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); ExitOnFailure(hr, "Failed to parse certificate attribute"); if (SCA_ACTION_INSTALL == saAction) // install operations need more data { hr = WcaReadStreamFromCaData(&pwz, &pbData, (DWORD_PTR*)&cbData); ExitOnFailure(hr, "Failed to parse certificate stream."); hr = WcaReadStringFromCaData(&pwz, &pwzPFXPassword); ExitOnFailure(hr, "Failed to parse certificate password."); } // Open the right store. hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwStoreLocation, pwzStore); MessageExitOnNullWithLastError1(hCertStore, hr, msierrCERTFailedOpen, "Failed to open certificate store: %ls", pwzStore); if (SCA_ACTION_INSTALL == saAction) // install operations need more data { // Uninstall existing versions of this package. Ignore any failures // This is needed to clean up the private key of a cert when we replace an existing cert // CertAddCertificateContextToStore(CERT_STORE_ADD_REPLACE_EXISTING) does not remove the private key if the cert is replaced UninstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName); hr = InstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName, pbData, cbData, pwzPFXPassword); ExitOnFailure(hr, "Failed to install certificate."); } else { Assert(SCA_ACTION_UNINSTALL == saAction); hr = UninstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName); ExitOnFailure(hr, "Failed to uninstall certificate."); } LExit: if (NULL != pwzPFXPassword && SUCCEEDED(StrSize(pwzPFXPassword, &cbPFXPassword))) { SecureZeroMemory(pwzPFXPassword, cbPFXPassword); } if (hCertStore) { if (!::CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG)) { WcaLog(LOGMSG_VERBOSE, "Cert store was closed but not all resources were freed. Error 0x%x", GetLastError()); } } ReleaseMem(pbData); ReleaseStr(pwzFilePath); ReleaseStr(pwzPFXPassword); ReleaseStr(pwzStore); ReleaseStr(pwzName); ReleaseStr(pwzCaData); return hr; }