Esempio n. 1
0
/********************************************************************
 SetVerboseLoggingAtom() - Sets one of two global Atoms to specify
                           if the install should do verbose logging.
                           Communicates the verbose setting to 
                           deferred CAs.
                           Set a negative case atom so that we can
                           distinguish between an unset atom and the
                           non-verbose case.  This helps prevent the
                           expensive regkey lookup for non-verbose.
********************************************************************/
HRESULT WIXAPI SetVerboseLoggingAtom(BOOL bValue)
{
    HRESULT hr = S_OK;
    ATOM atomVerbose = 0;

    atomVerbose = ::GlobalFindAtomW(L"WcaVerboseLogging");
    if (0 == atomVerbose &&  bValue)
    {
        atomVerbose = ::GlobalAddAtomW(L"WcaVerboseLogging");
        ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaVerboseLogging global atom.");
    }
    else if (0 != atomVerbose && !bValue)
    {
        ::SetLastError(ERROR_SUCCESS);
        ::GlobalDeleteAtom(atomVerbose);
        ExitOnLastError(hr, "Failed to delete WcaVerboseLogging global atom.");
    }

    atomVerbose = ::GlobalFindAtomW(L"WcaNotVerboseLogging");
    if (0 == atomVerbose && !bValue)
    {
        atomVerbose = ::GlobalAddAtomW(L"WcaNotVerboseLogging");
        ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaNotVerboseLogging global atom.");
    }
    else if (0 != atomVerbose && bValue)
    {
        ::SetLastError(ERROR_SUCCESS);
        ::GlobalDeleteAtom(atomVerbose);
        ExitOnLastError(hr, "Failed to delete WcaNotVerboseLogging global atom.");
    }

LExit:
    return hr;
}
Esempio n. 2
0
static HRESULT ParseWxlControls(
    __in IXMLDOMElement* pElement,
    __in WIX_LOCALIZATION* pWixLoc
    )
{
    HRESULT hr = S_OK;
    IXMLDOMNode* pixn = NULL;
    IXMLDOMNodeList* pixnl = NULL;
    DWORD dwIdx = 0;

    hr = XmlSelectNodes(pElement, L"UI|Control", &pixnl);
    ExitOnLastError(hr, "Failed to get UI child nodes of Wxl File.");

    hr = pixnl->get_length(reinterpret_cast<long*>(&pWixLoc->cLocControls));
    ExitOnLastError(hr, "Failed to get number of UI child nodes in Wxl File.");

    if (0 < pWixLoc->cLocControls)
    {
        pWixLoc->rgLocControls = static_cast<LOC_CONTROL*>(MemAlloc(sizeof(LOC_CONTROL) * pWixLoc->cLocControls, TRUE));
        ExitOnNull(pWixLoc->rgLocControls, hr, E_OUTOFMEMORY, "Failed to allocate memory for localized controls.");

        while (S_OK == (hr = XmlNextElement(pixnl, &pixn, NULL)))
        {
            hr = ParseWxlControl(pixn, dwIdx, pWixLoc);
            ExitOnFailure(hr, "Failed to parse localized control.");

            ++dwIdx;
            ReleaseNullObject(pixn);
        }

        hr = S_OK;
        ExitOnFailure(hr, "Failed to enumerate all localized controls.");
    }

LExit:
    if (FAILED(hr) && pWixLoc->rgLocControls)
    {
        for (DWORD idx = 0; idx < pWixLoc->cLocControls; ++idx)
        {
            ReleaseStr(pWixLoc->rgLocControls[idx].wzControl);
            ReleaseStr(pWixLoc->rgLocControls[idx].wzText);
        }

        ReleaseMem(pWixLoc->rgLocControls);
    }

    ReleaseObject(pixn);
    ReleaseObject(pixnl);

    return hr;
}
Esempio n. 3
0
/********************************************************************
 LoadEulaText - Reads data for Richedit control

********************************************************************/
void LoadEulaText(
    __in HWND hWnd
    )
{
    HRESULT hr = S_OK;

    ExitOnNull(hWnd, hr, ERROR_INVALID_HANDLE, "Invalid Handle passed to LoadEulaText");

    // Docs say this doesn't return any value
    ::SendMessageW(hWnd, EM_LIMITTEXT, static_cast<WPARAM>(lstrlen(vpszEulaText)), 0);

    EDITSTREAM es;
    ::ZeroMemory(&es, sizeof(es));
    es.pfnCallback = (EDITSTREAMCALLBACK)ReadStreamCallback;
    es.dwCookie = (DWORD)0;
    ::SendMessageW(hWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);

    if (0 != es.dwError)
    {
        ExitOnLastError(hr, "failed to load the EULA into the control");
    }

LExit:
    vhr = hr;
}
Esempio n. 4
0
/******************************************************************
 CaSchedServiceConfig - entry point for CaSchedServiceConfig Custom Action

 called as Type 1 CustomAction (binary DLL) from Windows Installer
 in InstallExecuteSequence before CaExecServiceConfig
********************************************************************/
extern "C" UINT __stdcall SchedServiceConfig(
	__in MSIHANDLE hInstall
	)
{
//	AssertSz(FALSE, "debug SchedServiceConfig");
	HRESULT hr = S_OK;
	UINT uiResult = ERROR_SUCCESS;
	DWORD dwError = 0;

	LPWSTR pwzData = NULL;
	int iData = 0;
	BOOL fExistingService = FALSE;

	PMSIHANDLE hView = NULL;
	PMSIHANDLE hRec = NULL;

	INSTALLSTATE isInstalled;
	INSTALLSTATE isAction;

	SC_HANDLE hSCM = NULL;
	SC_HANDLE hService = NULL;

	LPSERVICE_FAILURE_ACTIONSW psfa;

	LPWSTR pwzCustomActionData = NULL;
	LPWSTR pwzRollbackCustomActionData = NULL;

	DWORD cServices = 0;

	DWORD dwRestartDelay = 0;
	WCHAR wzActionName[32] = { 0 };

	DWORD dwSizeNeeded = 0;

	// initialize
	hr = WcaInitialize(hInstall, "SchedServiceConfig");
	ExitOnFailure(hr, "failed to initialize");

	//Get a handle to the service control manager
	hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
	if (hSCM == NULL)
		ExitOnLastError(hr, "failed to get handle to SCM");

	// loop through all the services to be configured
	hr = WcaOpenExecuteView(wzQUERY_SERVICECONFIG, &hView);
	ExitOnFailure(hr, "failed to open view on ServiceConfig table");

	while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
	{
		hr = WcaGetRecordInteger(hRec, QSC_NEWSERVICE, &iData);
		ExitOnFailure(hr, "failed to get object NewService");

		fExistingService = 1 != iData;

		// Get component name
		hr = WcaGetRecordString(hRec, QSC_COMPONENT, &pwzData);
		ExitOnFailure(hr, "failed to get component name");

		// check if we are installing this Component
		hr = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction);
		ExitOnFailure1(hr = HRESULT_FROM_WIN32(hr), "failed to get install state for Component: %S", pwzData);

		// We want to configure either a service we're installing or one already on the box
		if (WcaIsInstalling(isInstalled, isAction))
		{
			// Check if we're configuring an existing service
			if (fExistingService)
			{
				// Confirm the service is actually on the box
				hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData);
				ExitOnFailure(hr, "failed to get object NewService");

				//Get a handle to the service
				hService = ::OpenServiceW(hSCM, pwzData, SERVICE_QUERY_CONFIG);
				if (hService == NULL)
				{
					dwError = ::GetLastError();
					hr = HRESULT_FROM_WIN32(dwError);
					if (hr == ERROR_SERVICE_DOES_NOT_EXIST)
					{
						ExitOnFailure1(hr, "Service \"%s\" does not exist on this system.", pwzData);
					}
					else
					{
						ExitOnFailure1(hr, "Failed to get handle to the service \"%S\".", pwzData);
					}
				}

				// Get Current Service Config info
				if(!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &dwSizeNeeded) && ERROR_INSUFFICIENT_BUFFER != ::GetLastError())
				{
					ExitOnLastError(hr, "Failed to get current service config info.");
				}

				// Alloc space we were told we needed
				psfa = (LPSERVICE_FAILURE_ACTIONSW) MemAlloc(dwSizeNeeded, TRUE);
				ExitOnNull(psfa, hr, E_OUTOFMEMORY, "failed to allocate memory for service failure actions.");

				// Now do the real query
				if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)psfa, dwSizeNeeded, &dwSizeNeeded))
					ExitOnLastError(hr, "failed to Query Service.");

				// Build up rollback CA data so we can restore service state if necessary
				hr = WcaWriteStringToCaData(pwzData, &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

				// If this service struct is empty, fill in defualt values
				if(psfa->cActions < 3)
				{
					hr = WcaWriteStringToCaData(c_wzActionTypeNone, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

					hr = WcaWriteStringToCaData(c_wzActionTypeNone, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

					hr = WcaWriteStringToCaData(c_wzActionTypeNone, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
				}
				else
				{
					// psfa actually had actions defined, so use them

					// action 1
					hr = GetSCActionTypeString(psfa->lpsaActions[0].Type, (LPWSTR)wzActionName, 32);
					ExitOnFailure(hr, "failed to query SFA object");

					if (SC_ACTION_RESTART == psfa->lpsaActions[0].Type)
						dwRestartDelay = psfa->lpsaActions[0].Delay / 1000;

					hr = WcaWriteStringToCaData(wzActionName, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

					// action 2
					hr = GetSCActionTypeString(psfa->lpsaActions[1].Type, (LPWSTR)wzActionName, 32);
					ExitOnFailure(hr, "failed to query SFA object");

					if (SC_ACTION_RESTART == psfa->lpsaActions[1].Type)
						dwRestartDelay = psfa->lpsaActions[1].Delay / 1000;

					hr = WcaWriteStringToCaData(wzActionName, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

					// action 3
					hr = GetSCActionTypeString(psfa->lpsaActions[2].Type, (LPWSTR)wzActionName, 32);
					ExitOnFailure(hr, "failed to query SFA object");

					if (SC_ACTION_RESTART == psfa->lpsaActions[2].Type)
						dwRestartDelay = psfa->lpsaActions[2].Delay / 1000;

					hr = WcaWriteStringToCaData(wzActionName, &pwzRollbackCustomActionData);
					ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");
				}

				hr = WcaWriteIntegerToCaData(psfa->dwResetPeriod / (24 * 60 * 60), &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to CustomActionData");

				hr = WcaWriteIntegerToCaData(dwRestartDelay, &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to CustomActionData");

				// check for value being null
				if(!psfa->lpCommand)
					psfa->lpCommand = L"";
				hr = WcaWriteStringToCaData(psfa->lpCommand, &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

				// check for value being null
				if(!psfa->lpRebootMsg)
					psfa->lpRebootMsg = L"";
				hr = WcaWriteStringToCaData(psfa->lpRebootMsg, &pwzRollbackCustomActionData);
				ExitOnFailure(hr, "failed to add data to Rollback CustomActionData");

				// Clear up per-service values
				if(psfa)
					MemFree(psfa);
			}

			// add the data to the CustomActionData (for install)
			hr = WcaGetRecordFormattedString(hRec, QSC_SERVICENAME, &pwzData);
			ExitOnFailure(hr, "failed to get name of service");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_FIRSTFAILUREACTIONTYPE, &pwzData);
			ExitOnFailure(hr, "failed to get first failure action type");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_SECONDFAILUREACTIONTYPE, &pwzData);
			ExitOnFailure(hr, "failed to get second failure action type");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_THIRDFAILUREACTIONTYPE, &pwzData);
			ExitOnFailure(hr, "failed to get third failure action type");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordInteger(hRec, QSC_RESETPERIODINDAYS, &iData);
			if (hr == S_FALSE) // deal w/ possible null value
				iData = 0;
			ExitOnFailure(hr, "failed to get reset period in days between service restart attempts.");
			hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordInteger(hRec, QSC_RESTARTSERVICEDELAYINSECONDS, &iData);
			if (hr == S_FALSE) // deal w/ possible null value
				iData = 0;
			ExitOnFailure(hr, "failed to get server restart delay value.");
			hr = WcaWriteIntegerToCaData(iData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_PROGRAMCOMMANDLINE, &pwzData); // null value already dealt w/ properly
			ExitOnFailure(hr, "failed to get command line to run on service failure.");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			hr = WcaGetRecordString(hRec, QSC_REBOOTMESSAGE, &pwzData); // null value already dealt w/ properly
			ExitOnFailure(hr, "failed to get message to send to users when server reboots due to service failure.");
			hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
			ExitOnFailure(hr, "failed to add data to CustomActionData");

			cServices++;
			::CloseServiceHandle(hService);
			hService = NULL;
		}
	}

	// if we looped through all records all is well
	if (E_NOMOREITEMS == hr)
		hr = S_OK;
	ExitOnFailure(hr, "failed while looping through all objects to secure");

	// setup CustomActionData and add to progress bar for download
	if (pwzRollbackCustomActionData && *pwzRollbackCustomActionData)
	{
		Assert(0 < cServices);

		hr = WcaDoDeferredAction(L"ExecServiceConfigRollback", pwzRollbackCustomActionData, cServices * COST_SERVICECONFIG);
		ExitOnFailure(hr, "failed to schedule ExecSecureObjects action");
	}

	// schedule the custom action and add to progress bar
	if (pwzCustomActionData && *pwzCustomActionData)
	{
		Assert(0 < cServices);

		hr = WcaDoDeferredAction(L"ExecServiceConfig", pwzCustomActionData, cServices * COST_SERVICECONFIG);
		ExitOnFailure(hr, "failed to schedule ExecSecureObjects action");
	}

LExit:
	// Clean up handles
	if (hService != NULL)
		::CloseServiceHandle(hService);
	if (hSCM != NULL)
		::CloseServiceHandle(hSCM);

	ReleaseStr(pwzCustomActionData);
	ReleaseStr(pwzRollbackCustomActionData);
	ReleaseStr(pwzData);

	if (FAILED(hr))
		uiResult = ERROR_INSTALL_FAILURE;
	return WcaFinalize(uiResult);
}
Esempio n. 5
0
/********************************************************************
 CreateShare - create the file share on this computer

********************************************************************/
HRESULT CreateShare(SCA_SMBP* pssp)
{
    if (!pssp  || !(pssp->wzKey))
        return E_INVALIDARG;

    HRESULT hr = S_OK;
    PACL pACL = NULL;
    SHARE_INFO_502 si;
    NET_API_STATUS s;
    DWORD dwParamErr = 0;

    BOOL fShareExists = SUCCEEDED(DoesShareExist(pssp->wzKey));

    PSECURITY_DESCRIPTOR pSD = static_cast<PSECURITY_DESCRIPTOR>(MemAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH, TRUE));
    ExitOnNull(pSD, hr, E_OUTOFMEMORY, "Failed to allocate memory for security descriptor");

#pragma prefast(push)
#pragma prefast(disable:25029)
    if (!::InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
#pragma prefast(pop)
    {
        ExitOnLastError(hr, "failed to initialize security descriptor");
    }

    hr = AllocateAcl(pssp, &pACL);
    ExitOnFailure(hr, "Failed to allocate ACL for fileshare");

    if (NULL == pACL)
    {
        WcaLog(LOGMSG_VERBOSE, "Ignoring NULL DACL.");
    }
#pragma prefast(push)
#pragma prefast(disable:25028) // We only call this when pACL isn't NULL, so this call is safe according to the docs
    // add the ACL to the security descriptor.
    else if (!::SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE))
    {
        ExitOnLastError(hr, "Failed to set security descriptor");
    }
#pragma prefast(pop)

    // all that is left is to create the share
    FillShareInfo(&si, pssp, pSD);

    // Fail if the directory doesn't exist
    if (!DirExists(pssp->wzDirectory, NULL))
        ExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND), "Can't create a file share on directory that doesn't exist: %ls.", pssp->wzDirectory);

    WcaLog(LOGMSG_VERBOSE, "Creating file share on directory \'%ls\' named \'%ls\'.", pssp->wzDirectory, pssp->wzKey);

    if (!fShareExists)
    {
        s = ::NetShareAdd(NULL, 502, (BYTE*) &si, &dwParamErr);
        WcaLog(LOGMSG_VERBOSE, "Adding a new file share.");
    }
    else
    {
        // The share exists.   Write our new permissions over the top.
        s = ::NetShareSetInfo(NULL, pssp->wzKey, 502, (BYTE*) &si, &dwParamErr);
        WcaLog(LOGMSG_VERBOSE, "Setting permissions on existing share.");
    }

    if (NERR_Success != s)
    {
        hr = E_FAIL;
        if (!fShareExists && NERR_DuplicateShare == s)
            WcaLog(LOGMSG_VERBOSE, "Duplicate error when existence check failed.");

        // error codes listed above.
        ExitOnFailure1(hr, "Failed to create/modify file share: Err: %d", s);
    }

LExit:
    if (pACL)
    {
        ::LocalFree(pACL);
    }

    ReleaseMem(pSD);

    return hr;
}
Esempio n. 6
0
/******************************************************************
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);
}
Esempio n. 7
0
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);
}
Esempio n. 8
0
HRESULT WIXAPI QuietExecEx(
    __inout_z LPWSTR wzCommand,
    __in DWORD dwTimeout,
    __in BOOL fLogCommand,
    __in BOOL fLogOutput
    )
{
    HRESULT hr = S_OK;
    PROCESS_INFORMATION oProcInfo;
    STARTUPINFOW oStartInfo;
    DWORD dwExitCode = ERROR_SUCCESS;
    HANDLE hOutRead = INVALID_HANDLE_VALUE;
    HANDLE hOutWrite = INVALID_HANDLE_VALUE;
    HANDLE hErrWrite = INVALID_HANDLE_VALUE;
    HANDLE hInRead = INVALID_HANDLE_VALUE;
    HANDLE hInWrite = INVALID_HANDLE_VALUE;

    memset(&oProcInfo, 0, sizeof(oProcInfo));
    memset(&oStartInfo, 0, sizeof(oStartInfo));

    // Create output redirect pipes
    hr = CreatePipes(&hOutRead, &hOutWrite, &hErrWrite, &hInRead, &hInWrite);
    ExitOnFailure(hr, "Failed to create output pipes");

    // Set up startup structure
    oStartInfo.cb = sizeof(STARTUPINFOW);
    oStartInfo.dwFlags = STARTF_USESTDHANDLES;
    oStartInfo.hStdInput = hInRead;
    oStartInfo.hStdOutput = hOutWrite;
    oStartInfo.hStdError = hErrWrite;

    // Log command if we were asked to do so
    if (fLogCommand)
    {
        WcaLog(LOGMSG_VERBOSE, "%ls", wzCommand);
    }

#pragma prefast(suppress:25028)
    if (::CreateProcessW(NULL,
        wzCommand, // command line
        NULL, // security info
        NULL, // thread info
        TRUE, // inherit handles
        ::GetPriorityClass(::GetCurrentProcess()) | CREATE_NO_WINDOW, // creation flags
        NULL, // environment
        NULL, // cur dir
        &oStartInfo,
        &oProcInfo))
    {
        ReleaseFile(oProcInfo.hThread);

        // Close child output/input handles so it doesn't hang
        ReleaseFile(hOutWrite);
        ReleaseFile(hErrWrite);
        ReleaseFile(hInRead);

        // Log output if we were asked to do so; otherwise just read the output handle
        HandleOutput(fLogOutput, hOutRead);

        // Wait for everything to finish
        ::WaitForSingleObject(oProcInfo.hProcess, dwTimeout);
        if (!::GetExitCodeProcess(oProcInfo.hProcess, &dwExitCode))
        {
            dwExitCode = ERROR_SEM_IS_SET;
        }

        ReleaseFile(hOutRead);
        ReleaseFile(hInWrite);
        ReleaseFile(oProcInfo.hProcess);
    }
    else
    {
        ExitOnLastError(hr, "Command failed to execute.");
    }

    ExitOnWin32Error(dwExitCode, hr, "Command line returned an error.");

LExit:
    return hr;
}
Esempio n. 9
0
static HRESULT CreatePipes(
    __out HANDLE *phOutRead,
    __out HANDLE *phOutWrite,
    __out HANDLE *phErrWrite,
    __out HANDLE *phInRead,
    __out HANDLE *phInWrite
    )
{
    Assert(phOutRead);
    Assert(phOutWrite);
    Assert(phErrWrite);
    Assert(phInRead);
    Assert(phInWrite);

    HRESULT hr = S_OK;
    SECURITY_ATTRIBUTES sa;
    HANDLE hOutTemp = INVALID_HANDLE_VALUE;
    HANDLE hInTemp = INVALID_HANDLE_VALUE;

    HANDLE hOutRead = INVALID_HANDLE_VALUE;
    HANDLE hOutWrite = INVALID_HANDLE_VALUE;
    HANDLE hErrWrite = INVALID_HANDLE_VALUE;
    HANDLE hInRead = INVALID_HANDLE_VALUE;
    HANDLE hInWrite = INVALID_HANDLE_VALUE;

    // Fill out security structure so we can inherit handles
    ::ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;

    // Create pipes
    if (!::CreatePipe(&hOutTemp, &hOutWrite, &sa, 0))
    {
        ExitOnLastError(hr, "Failed to create output pipe");
    }

    if (!::CreatePipe(&hInRead, &hInTemp, &sa, 0))
    {
        ExitOnLastError(hr, "Failed to create input pipe");
    }


    // Duplicate output pipe so standard error and standard output write to
    // the same pipe
    if (!::DuplicateHandle(::GetCurrentProcess(), hOutWrite, ::GetCurrentProcess(), &hErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS))
    {
        ExitOnLastError(hr, "Failed to duplicate write handle");
    }

    // We need to create new output read and input write handles that are
    // non inheritable.  Otherwise it creates handles that can't be closed.
    if (!::DuplicateHandle(::GetCurrentProcess(), hOutTemp, ::GetCurrentProcess(), &hOutRead, 0, FALSE, DUPLICATE_SAME_ACCESS))
    {
        ExitOnLastError(hr, "Failed to duplicate output pipe");
    }

    if (!::DuplicateHandle(::GetCurrentProcess(), hInTemp, ::GetCurrentProcess(), &hInWrite, 0, FALSE, DUPLICATE_SAME_ACCESS))
    {
        ExitOnLastError(hr, "Failed to duplicate input pipe");
    }

    // now that everything has succeeded, assign to the outputs
    *phOutRead = hOutRead;
    hOutRead = INVALID_HANDLE_VALUE;

    *phOutWrite = hOutWrite;
    hOutWrite = INVALID_HANDLE_VALUE;

    *phErrWrite = hErrWrite;
    hErrWrite = INVALID_HANDLE_VALUE;

    *phInRead = hInRead;
    hInRead = INVALID_HANDLE_VALUE;

    *phInWrite = hInWrite;
    hInWrite = INVALID_HANDLE_VALUE;

LExit:
    ReleaseFile(hOutRead);
    ReleaseFile(hOutWrite);
    ReleaseFile(hErrWrite);
    ReleaseFile(hInRead);
    ReleaseFile(hInWrite);
    ReleaseFile(hOutTemp);
    ReleaseFile(hInTemp);

    return hr;
}
Esempio n. 10
0
static HRESULT HandleOutput(
    __in BOOL fLogOutput,
    __in HANDLE hRead
    )
{
    BYTE *pBuffer = NULL;
    LPWSTR szLog = NULL;
    LPWSTR szTemp = NULL;
    LPWSTR pEnd = NULL;
    LPWSTR pNext = NULL;
    LPWSTR sczEscaped = NULL;
    LPSTR szWrite = NULL;
    DWORD dwBytes = OUTPUT_BUFFER;
    BOOL bFirst = TRUE;
    BOOL bUnicode = TRUE;
    HRESULT hr = S_OK;

    // Get buffer for output
    pBuffer = static_cast<BYTE *>(MemAlloc(OUTPUT_BUFFER, FALSE));
    ExitOnNull(pBuffer, hr, E_OUTOFMEMORY, "Failed to allocate buffer for output.");

    while (0 != dwBytes)
    {
        ::ZeroMemory(pBuffer, OUTPUT_BUFFER);
        if (!::ReadFile(hRead, pBuffer, OUTPUT_BUFFER - 1, &dwBytes, NULL) && GetLastError() != ERROR_BROKEN_PIPE)
        {
            ExitOnLastError(hr, "Failed to read from handle.");
        }

        if (fLogOutput)
        {
            // Check for UNICODE or ANSI output
            if (bFirst)
            {
                if ((isgraph(pBuffer[0]) && isgraph(pBuffer[1])) ||
                    (isgraph(pBuffer[0]) && isspace(pBuffer[1])) ||
                    (isspace(pBuffer[0]) && isgraph(pBuffer[1])) ||
                    (isspace(pBuffer[0]) && isspace(pBuffer[1])))
                {
                    bUnicode = FALSE;
                }

                bFirst = FALSE;
            }

            // Keep track of output
            if (bUnicode)
            {
                hr = StrAllocConcat(&szLog, (LPCWSTR)pBuffer, 0);
                ExitOnFailure(hr, "Failed to concatenate output strings");
            }
            else
            {
                hr = StrAllocStringAnsi(&szTemp, (LPCSTR)pBuffer, 0, CP_OEMCP);
                ExitOnFailure(hr, "Failed to allocate output string");
                hr = StrAllocConcat(&szLog, szTemp, 0);
                ExitOnFailure(hr, "Failed to concatenate output strings");
            }

            // Log each line of the output
            pNext = szLog;
            pEnd = wcschr(szLog, L'\r');
            if (NULL == pEnd)
            {
                pEnd = wcschr(szLog, L'\n');
            }
            while (pEnd && *pEnd)
            {
                // Find beginning of next line
                pEnd[0] = 0;
                ++pEnd;
                if ((pEnd[0] == L'\r') || (pEnd[0] == L'\n'))
                {
                    ++pEnd;
                }

                // Log output
                hr = StrAllocString(&sczEscaped, pNext, 0);
                ExitOnFailure(hr, "Failed to allocate copy of string");

                hr = StrReplaceStringAll(&sczEscaped, L"%", L"%%");
                ExitOnFailure(hr, "Failed to escape percent signs in string");

                hr = StrAnsiAllocString(&szWrite, sczEscaped, 0, CP_OEMCP);
                ExitOnFailure(hr, "Failed to convert output to ANSI");
                WcaLog(LOGMSG_STANDARD, szWrite);

                // Next line
                pNext = pEnd;
                pEnd = wcschr(pNext, L'\r');
                if (NULL == pEnd)
                {
                    pEnd = wcschr(pNext, L'\n');
                }
            }

            hr = StrAllocString(&szTemp, pNext, 0);
            ExitOnFailure(hr, "Failed to allocate string");

            hr = StrAllocString(&szLog, szTemp, 0);
            ExitOnFailure(hr, "Failed to allocate string");
        }
    }

    // Print any text that didn't end with a new line
    if (szLog && *szLog)
    {
        hr = StrReplaceStringAll(&szLog, L"%", L"%%");
        ExitOnFailure(hr, "Failed to escape percent signs in string");

        hr = StrAnsiAllocString(&szWrite, szLog, 0, CP_OEMCP);
        ExitOnFailure(hr, "Failed to convert output to ANSI");

        WcaLog(LOGMSG_VERBOSE, szWrite);
    }

LExit:
    ReleaseMem(pBuffer);

    ReleaseStr(szLog);
    ReleaseStr(szTemp);
    ReleaseStr(szWrite);
    ReleaseStr(sczEscaped);

    return hr;
}