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 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 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 MqiRollbackRemoveMessageQueuePermissions( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // add message queue permission hr = SetMessageQueuePermissions(&attrs, FALSE); if (FAILED(hr)) WcaLog(LOGMSG_STANDARD, "Failed to rollback remove message queue permission, hr: 0x%x, key: %S", hr, attrs.pwzKey); } hr = S_OK; LExit: // clean up FreeMessageQueuePermissionAttributes(&attrs); return hr; }
/****************************************************************** 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); }
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; }
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; }
/****************************************************************** 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); }
HRESULT MqiRemoveMessageQueuePermissions( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // progress message hr = PcaActionDataMessage(1, attrs.pwzPathName); ExitOnFailure(hr, "Failed to send progress messages"); // add message queue permission hr = SetMessageQueuePermissions(&attrs, TRUE); ExitOnFailure(hr, "Failed to remove message queue permission"); // progress tics hr = WcaProgressMessage(COST_MESSAGE_QUEUE_PERMISSION_ADD, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeMessageQueuePermissionAttributes(&attrs); return hr; }
HRESULT MqiDeleteMessageQueues( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueueAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // progress message hr = PcaActionDataMessage(1, attrs.pwzPathName); ExitOnFailure1(hr, "Failed to send progress messages, key: %S", attrs.pwzKey); // create message queue hr = DeleteMessageQueue(&attrs); ExitOnFailure1(hr, "Failed to delete message queue, key: %S", attrs.pwzKey); // progress tics hr = WcaProgressMessage(COST_MESSAGE_QUEUE_DELETE, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeMessageQueueAttributes(&attrs); 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; }
HRESULT CpiConfigureApplicationRoles( LPWSTR* ppwzData, HANDLE hRollbackFile ) { HRESULT hr = S_OK; CPI_APPLICATION_ROLE_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // read action text hr = CpiActionStartMessage(ppwzData, FALSE); ExitOnFailure(hr, "Failed to send action start message"); // ger count int iCnt = 0; hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); // write count to rollback file hr = CpiWriteIntegerToRollbackFile(hRollbackFile, iCnt); ExitOnFailure(hr, "Failed to write count to rollback file"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadApplicationRoleAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // progress message hr = CpiActionDataMessage(1, attrs.pwzName); ExitOnFailure(hr, "Failed to send progress messages"); if (S_FALSE == hr) ExitFunction(); // write key to rollback file hr = CpiWriteKeyToRollbackFile(hRollbackFile, attrs.pwzKey); ExitOnFailure(hr, "Failed to write key to rollback file"); // action switch (attrs.iActionType) { case atCreate: hr = CreateApplicationRole(&attrs); ExitOnFailure1(hr, "Failed to create application role, key: %S", attrs.pwzKey); break; case atRemove: hr = RemoveApplicationRole(&attrs); ExitOnFailure1(hr, "Failed to remove application role, key: %S", attrs.pwzKey); break; } // write completion status to rollback file hr = CpiWriteIntegerToRollbackFile(hRollbackFile, 1); ExitOnFailure(hr, "Failed to write completion status to rollback file"); // progress hr = WcaProgressMessage(attrs.iActionCost, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeApplicationRoleAttributes(&attrs); 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); }
/****************************************************************** 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); }
HRESULT CpiRollbackConfigureUsersInApplicationRoles( LPWSTR* ppwzData, CPI_ROLLBACK_DATA* pRollbackDataList ) { HRESULT hr = S_OK; int iRollbackStatus; CPI_USER_IN_APPLICATION_ROLE_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // read action text hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); ExitOnFailure(hr, "Failed to send action start message"); // get count int iCnt = 0; hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadUsersInApplicationRoleAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // rollback status hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); if (S_FALSE == hr) continue; // not found, nothing to rollback // progress message hr = CpiActionDataMessage(1, attrs.pwzRoleName); ExitOnFailure(hr, "Failed to send progress messages"); if (S_FALSE == hr) ExitFunction(); // action switch (attrs.iActionType) { case atCreate: hr = CreateUsersInApplicationRole(&attrs); if (FAILED(hr)) WcaLog(LOGMSG_STANDARD, "Failed to add user to application role, hr: 0x%x, key: %S", hr, attrs.pwzKey); break; case atRemove: hr = RemoveUsersInApplicationRole(&attrs); if (FAILED(hr)) WcaLog(LOGMSG_STANDARD, "Failed to remove user from application role, hr: 0x%x, key: %S", hr, attrs.pwzKey); break; } // check rollback status if (0 == iRollbackStatus) continue; // operation did not complete, skip progress // progress hr = WcaProgressMessage(attrs.iActionCost, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeUsersInApplicationRoleAttributes(&attrs); return hr; }
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; }
/****************************************************************** 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); }
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); }
/****************************************************************** 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); }
/****************************************************************** 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); }
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); }
/****************************************************************** 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; }
/****************************************************************** 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); }
/****************************************************************** 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); }
HRESULT CpiRollbackConfigurePartitionUsers( LPWSTR* ppwzData, CPI_ROLLBACK_DATA* pRollbackDataList ) { HRESULT hr = S_OK; int iRollbackStatus; CPI_PARTITION_USER_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // read action text hr = CpiActionStartMessage(ppwzData, NULL == pRollbackDataList); ExitOnFailure(hr, "Failed to send action start message"); // get count int iCnt = 0; hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read partition attributes from CustomActionData hr = ReadPartitionUserAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // rollback status hr = CpiFindRollbackStatus(pRollbackDataList, attrs.pwzKey, &iRollbackStatus); if (S_FALSE == hr) continue; // not found, nothing to rollback // progress message hr = CpiActionDataMessage(1, attrs.pwzAccount); ExitOnFailure(hr, "Failed to send progress messages"); if (S_FALSE == hr) ExitFunction(); // action switch (attrs.iActionType) { case atCreate: hr = CreatePartitionUser(&attrs); ExitOnFailure1(hr, "Failed to create partition user, key: %S", attrs.pwzKey); break; case atRemove: hr = RemovePartitionUser(&attrs); ExitOnFailure1(hr, "Failed to remove partition user, key: %S", attrs.pwzKey); break; } // check rollback status if (0 == iRollbackStatus) continue; // operation did not complete, skip progress // progress hr = WcaProgressMessage(attrs.iActionCost, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreePartitionUserAttributes(&attrs); return hr; }