Esempio n. 1
0
extern "C" HRESULT MspEngineDetectPackage(
    __in BURN_PACKAGE* pPackage,
    __in BURN_USER_EXPERIENCE* pUserExperience
    )
{
    HRESULT hr = S_OK;
    int nResult = IDOK;
    LPWSTR sczState = NULL;

    if (0 == pPackage->Msp.cTargetProductCodes)
    {
        pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
    }
    else
    {
        // Start the package state at the the highest state then loop through all the
        // target product codes and end up setting the current state to the lowest
        // package state applied to the the target product codes.
        pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED;

        for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
        {
            BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i;

            hr = WiuGetPatchInfoEx(pPackage->Msp.sczPatchCode, pTargetProduct->wzTargetProductCode, NULL, pTargetProduct->context, INSTALLPROPERTY_PATCHSTATE, &sczState);
            if (SUCCEEDED(hr))
            {
                switch (*sczState)
                {
                case '1':
                    pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT;
                    break;

                case '2':
                    pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED;
                    break;

                case '4':
                    pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE;
                    break;

                default:
                    pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
                    break;
                }
            }
            else if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PATCH) == hr)
            {
                pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
                hr = S_OK;
            }
            ExitOnFailure2(hr, "Failed to get patch information for patch code: %ls, target product code: %ls", pPackage->Msp.sczPatchCode, pTargetProduct->wzTargetProductCode);

            if (pPackage->currentState > pTargetProduct->patchPackageState)
            {
                pPackage->currentState = pTargetProduct->patchPackageState;
            }

            nResult = pUserExperience->pUserExperience->OnDetectTargetMsiPackage(pPackage->sczId, pTargetProduct->wzTargetProductCode, pTargetProduct->patchPackageState);
            hr = UserExperienceInterpretResult(pUserExperience, MB_OKCANCEL, nResult);
            ExitOnRootFailure(hr, "UX aborted detect target MSI package.");
        }
    }

LExit:
    ReleaseStr(sczState);

    return hr;
}
Esempio n. 2
0
HRESULT ScaWebErrorRead(
    SCA_WEB_ERROR **ppsweList,
    __inout LPWSTR *ppwzCustomActionData
)
{
//    AssertSz(0, "Debug ScaWebErrorRead here");
    HRESULT hr = S_OK;
    MSIHANDLE hRec;
    LPWSTR pwzData = NULL;
    SCA_WEB_ERROR* pswe;
    WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;

    ExitOnNull(ppsweList, hr, E_INVALIDARG, "Failed to read web error, because no web error was provided to read");

    hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
    ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");

    if (0 == WcaGetQueryRecords(hWrapQuery))
    {
        WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebErrorRead() - required tables not present.");
        ExitFunction1(hr = S_FALSE);
    }

    // loop through all the web errors
    while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
    {
        hr = AddWebErrorToList(ppsweList);
        ExitOnFailure(hr, "failed to add web error to list");

        pswe = *ppsweList;

        hr = WcaGetRecordInteger(hRec, weqErrorCode, &(pswe->iErrorCode));
        ExitOnFailure(hr, "failed to get IIsWebError.ErrorCode");

        hr = WcaGetRecordInteger(hRec, weqSubCode, &(pswe->iSubCode));
        ExitOnFailure(hr, "failed to get IIsWebError.SubCode");

        hr = WcaGetRecordInteger(hRec, weqParentType, &(pswe->iParentType));
        ExitOnFailure(hr, "failed to get IIsWebError.ParentType");

        hr = WcaGetRecordString(hRec, weqParentValue, &pwzData);
        ExitOnFailure(hr, "Failed to get IIsWebError.ParentValue");
        hr = ::StringCchCopyW(pswe->wzParentValue, countof(pswe->wzParentValue), pwzData);
        ExitOnFailure(hr, "Failed to copy IIsWebError.ParentValue");

        hr = WcaGetRecordString(hRec, weqFile, &pwzData);
        ExitOnFailure(hr, "Failed to get IIsWebError.File");
        hr = ::StringCchCopyW(pswe->wzFile, countof(pswe->wzFile), pwzData);
        ExitOnFailure(hr, "Failed to copy IIsWebError.File");

        hr = WcaGetRecordString(hRec, weqURL, &pwzData);
        ExitOnFailure(hr, "Failed to get IIsWebError.URL");
        hr = ::StringCchCopyW(pswe->wzURL, countof(pswe->wzURL), pwzData);
        ExitOnFailure(hr, "Failed to copy IIsWebError.URL");

        // If they've specified both a file and a URL, that's invalid
        if (*(pswe->wzFile) && *(pswe->wzURL))
            ExitOnFailure2(hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA), "Both File and URL specified for web error.  File: %ls, URL: %ls", pswe->wzFile, pswe->wzURL);
    }

    if (E_NOMOREITEMS == hr)
    {
        hr = S_OK;
    }
    ExitOnFailure(hr, "Failure while processing web errors");

LExit:
    WcaFinishUnwrapQuery(hWrapQuery);

    ReleaseStr(pwzData);

    return hr;
}
Esempio n. 3
0
extern "C" HRESULT MspEngineExecutePackage(
    __in_opt HWND hwndParent,
    __in BURN_EXECUTE_ACTION* pExecuteAction,
    __in BURN_VARIABLES* pVariables,
    __in BOOL fRollback,
    __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler,
    __in LPVOID pvContext,
    __out BOOTSTRAPPER_APPLY_RESTART* pRestart
    )
{
    HRESULT hr = S_OK;
    INSTALLUILEVEL uiLevel = pExecuteAction->mspTarget.pPackage->Msp.fDisplayInternalUI ? INSTALLUILEVEL_DEFAULT : static_cast<INSTALLUILEVEL>(INSTALLUILEVEL_NONE | INSTALLUILEVEL_SOURCERESONLY);
    WIU_MSI_EXECUTE_CONTEXT context = { };
    WIU_RESTART restart = WIU_RESTART_NONE;

    LPWSTR sczCachedDirectory = NULL;
    LPWSTR sczMspPath = NULL;
    LPWSTR sczPatches = NULL;
    LPWSTR sczProperties = NULL;
    LPWSTR sczObfuscatedProperties = NULL;

    // default to "verbose" logging
    DWORD dwLogMode = WIU_LOG_DEFAULT | INSTALLLOGMODE_VERBOSE;

    // get cached MSP paths
    for (DWORD i = 0; i < pExecuteAction->mspTarget.cOrderedPatches; ++i)
    {
        LPCWSTR wzAppend = NULL;
        BURN_PACKAGE* pMspPackage = pExecuteAction->mspTarget.rgOrderedPatches[i].pPackage;
        AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Invalid package type added to ordered patches.");

        if (BOOTSTRAPPER_ACTION_STATE_INSTALL == pExecuteAction->mspTarget.action)
        {
            hr = CacheGetCompletedPath(pMspPackage->fPerMachine, pMspPackage->sczCacheId, &sczCachedDirectory);
            ExitOnFailure1(hr, "Failed to get cached path for MSP package: %ls", pMspPackage->sczId);

            // TODO: Figure out if this makes sense -- the variable is set to the last patch's path only
            // Best effort to set the execute package cache folder variable.
            VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, sczCachedDirectory, TRUE);

            hr = PathConcat(sczCachedDirectory, pMspPackage->rgPayloads[0].pPayload->sczFilePath, &sczMspPath);
            ExitOnFailure(hr, "Failed to build MSP path.");

            wzAppend = sczMspPath;
        }
        else // uninstall
        {
            wzAppend = pMspPackage->Msp.sczPatchCode;
        }

        if (NULL != sczPatches)
        {
            hr = StrAllocConcat(&sczPatches, L";", 0);
            ExitOnFailure(hr, "Failed to semi-colon delimit patches.");
        }

        hr = StrAllocConcat(&sczPatches, wzAppend, 0);
        ExitOnFailure(hr, "Failed to append patch.");
    }

    // Best effort to set the execute package action variable.
    VariableSetNumeric(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_ACTION, pExecuteAction->mspTarget.action, TRUE);

    // Wire up the external UI handler and logging.
    hr = WiuInitializeExternalUI(pfnMessageHandler, uiLevel, hwndParent, pvContext, fRollback, &context);
    ExitOnFailure(hr, "Failed to initialize external UI handler.");

    //if (BURN_LOGGING_LEVEL_DEBUG == logLevel)
    //{
    //    dwLogMode | INSTALLLOGMODE_EXTRADEBUG;
    //}

    if (pExecuteAction->mspTarget.sczLogPath && *pExecuteAction->mspTarget.sczLogPath)
    {
        hr = WiuEnableLog(dwLogMode, pExecuteAction->mspTarget.sczLogPath, 0);
        ExitOnFailure2(hr, "Failed to enable logging for package: %ls to: %ls", pExecuteAction->mspTarget.pPackage->sczId, pExecuteAction->mspTarget.sczLogPath);
    }

    // set up properties
    hr = MsiEngineConcatProperties(pExecuteAction->mspTarget.pPackage->Msp.rgProperties, pExecuteAction->mspTarget.pPackage->Msp.cProperties, pVariables, fRollback, &sczProperties, FALSE);
    ExitOnFailure(hr, "Failed to add properties to argument string.");

    hr = MsiEngineConcatProperties(pExecuteAction->mspTarget.pPackage->Msp.rgProperties, pExecuteAction->mspTarget.pPackage->Msp.cProperties, pVariables, fRollback, &sczObfuscatedProperties, TRUE);
    ExitOnFailure(hr, "Failed to add properties to obfuscated argument string.");

    LogId(REPORT_STANDARD, MSG_APPLYING_PATCH_PACKAGE, pExecuteAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pExecuteAction->mspTarget.action), sczPatches, sczObfuscatedProperties, pExecuteAction->mspTarget.sczTargetProductCode);

    //
    // Do the actual action.
    //
    switch (pExecuteAction->mspTarget.action)
    {
    case BOOTSTRAPPER_ACTION_STATE_INSTALL: __fallthrough;
    case BOOTSTRAPPER_ACTION_STATE_REPAIR:
        hr = StrAllocConcatSecure(&sczProperties, L" PATCH=\"", 0);
        ExitOnFailure(hr, "Failed to add PATCH property on install.");

        hr = StrAllocConcatSecure(&sczProperties, sczPatches, 0);
        ExitOnFailure(hr, "Failed to add patches to PATCH property on install.");

        hr = StrAllocConcatSecure(&sczProperties, L"\" REBOOT=ReallySuppress", 0);
        ExitOnFailure(hr, "Failed to add reboot suppression property on install.");

        hr = WiuConfigureProductEx(pExecuteAction->mspTarget.sczTargetProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, sczProperties, &restart);
        ExitOnFailure(hr, "Failed to install MSP package.");
        break;

    case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
        hr = StrAllocConcatSecure(&sczProperties, L" REBOOT=ReallySuppress", 0);
        ExitOnFailure(hr, "Failed to add reboot suppression property on uninstall.");

        // Ignore all dependencies, since the Burn engine already performed the check.
        hr = StrAllocFormattedSecure(&sczProperties, L"%ls %ls=ALL", sczProperties, DEPENDENCY_IGNOREDEPENDENCIES);
        ExitOnFailure(hr, "Failed to add the list of dependencies to ignore to the properties.");

        hr = WiuRemovePatches(sczPatches, pExecuteAction->mspTarget.sczTargetProductCode, sczProperties, &restart);
        ExitOnFailure(hr, "Failed to uninstall MSP package.");
        break;
    }

LExit:
    WiuUninitializeExternalUI(&context);

    ReleaseStr(sczCachedDirectory);
    ReleaseStr(sczMspPath);
    StrSecureZeroFreeString(sczProperties);
    ReleaseStr(sczObfuscatedProperties);
    ReleaseStr(sczPatches);

    switch (restart)
    {
        case WIU_RESTART_NONE:
            *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE;
            break;

        case WIU_RESTART_REQUIRED:
            *pRestart = BOOTSTRAPPER_APPLY_RESTART_REQUIRED;
            break;

        case WIU_RESTART_INITIATED:
            *pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED;
            break;
    }

    // Best effort to clear the execute package cache folder and action variables.
    VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, NULL, TRUE);
    VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_ACTION, NULL, TRUE);

    return hr;
}
Esempio n. 4
0
HRESULT ScaWriteWebError(IMSAdminBase* piMetabase, int iParentType, LPCWSTR wzRoot, SCA_WEB_ERROR* psweList)
{
//    AssertSz(0, "Debug ScaWriteWebError here");
    Assert(*wzRoot && psweList);

    HRESULT hr = S_OK;

    DWORD cchData = 0;
    LPWSTR pwzSearchKey = NULL;
    LPWSTR pwz = NULL;
    LPWSTR pwzErrors = NULL;

    LPWSTR pwzCodeSubCode = NULL;
    LPWSTR pwzAcceptableCodeSubCode = NULL;
    LPCWSTR wzFoundCodeSubCode = NULL;
    DWORD_PTR dwFoundCodeSubCodeIndex = 0xFFFFFFFF;
    BOOL fOldValueFound = FALSE;
    LPWSTR pwzAcceptableErrors = NULL;

    LPWSTR pwzNewError = NULL;

    METADATA_RECORD mr;
    ::ZeroMemory(&mr, sizeof(mr));

    ExitOnNull(piMetabase, hr, E_INVALIDARG, "Failed to write web error, because no metabase was provided");
    ExitOnNull(wzRoot, hr, E_INVALIDARG, "Failed to write web error, because no root was provided");

    // get the set of all valid custom errors from the metabase
    mr.dwMDIdentifier = MD_CUSTOM_ERROR_DESC;
    mr.dwMDAttributes = METADATA_INHERIT;
    mr.dwMDUserType = IIS_MD_UT_SERVER;
    mr.dwMDDataType = ALL_METADATA;
    mr.dwMDDataLen = cchData = 0;
    mr.pbMDData = NULL;

    hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/Info", &mr);
    ExitOnFailure(hr, "Unable to get set of acceptable error codes for this server.");

    pwzAcceptableErrors = reinterpret_cast<LPWSTR>(mr.pbMDData);

    // Check if web errors already exist here
    mr.dwMDIdentifier = MD_CUSTOM_ERROR;
    mr.dwMDAttributes = METADATA_INHERIT;
    mr.dwMDUserType = IIS_MD_UT_SERVER;
    mr.dwMDDataType = ALL_METADATA;
    mr.dwMDDataLen = cchData = 0;
    mr.pbMDData = NULL;

    hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzRoot, &mr);
    if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr)
    {
        //
        // If we don't have one already, find an appropriate one to start with
        //

        // we can walk up key by key and look for custom errors to inherit

        hr = StrAllocConcat(&pwzSearchKey, wzRoot, 0);
        ExitOnFailure1(hr, "Failed to copy root string: %ls", wzRoot);

        pwz = pwzSearchKey + lstrlenW(pwzSearchKey);

        while (NULL == pwzErrors)
        {
            // find the last slash
            while (*pwz != '/' && pwz != pwzSearchKey)
                pwz --;

            if (pwz == pwzSearchKey)
                break;

            *pwz = L'\0';

            // Try here.  If it's not found, keep walking up the path
            hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, pwzSearchKey, &mr);
            if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr)
                hr = S_FALSE;
            ExitOnFailure1(hr, "failed to discover default error values to start with for web root: %ls while walking up the tree", wzRoot);

            if (S_OK == hr)
            {
                pwzErrors = reinterpret_cast<LPWSTR>(mr.pbMDData);
                break;
            }

            // Don't keep going if we're at the root
            if (0 == lstrcmpW(pwz + 1, L"W3SVC"))
                break;
        }
    }
    else
    {
        pwzErrors = reinterpret_cast<LPWSTR>(mr.pbMDData);
    }
    ExitOnFailure1(hr, "failed to discover default error values to start with for web root: %ls", wzRoot);

    // The above code should have come up with some value to start pwzErrors off with.  Make sure it did.
    if (NULL == pwzErrors)
    {
        ExitOnFailure1(hr = E_UNEXPECTED, "failed to discover default error values to start with for web root: %ls", wzRoot);
    }

    // Loop through the web errors
    for (SCA_WEB_ERROR* pswe = psweList; pswe; pswe = pswe->psweNext)
    {
        // Assume that we will have to replace
        fOldValueFound = TRUE;

        // If the subcode is 0, that means "*" in MD_CUSTOM_ERROR (thus the special formatting logic)
        if (0 == pswe->iSubCode)
        {
            hr = StrAllocFormatted(&pwzCodeSubCode, L"%d,*", pswe->iErrorCode);
            ExitOnFailure(hr, "failed to create error code string while installing web error");
        }
        else
        {
            hr = StrAllocFormatted(&pwzCodeSubCode, L"%d,%d", pswe->iErrorCode, pswe->iSubCode);
            ExitOnFailure(hr, "failed to create error code,subcode string while installing web error");
        }

        hr = MultiSzFindSubstring(pwzErrors, pwzCodeSubCode, &dwFoundCodeSubCodeIndex, &wzFoundCodeSubCode);
        ExitOnFailure1(hr, "failed to find existing error code,subcode: %ls", pwzCodeSubCode);

        // If we didn't find this error code/sub code pair in the list already, make sure it's acceptable to add
        if (S_FALSE == hr)
        {
            //
            // Make sure this error code/sub code pair is in the "acceptable" list
            //

            // If the subcode is 0, that means "0" in MD_CUSTOM_ERROR_DESC (no special formatting logic needed)
            hr = StrAllocFormatted(&pwzAcceptableCodeSubCode, L"%d,%d", pswe->iErrorCode, pswe->iSubCode);
            ExitOnFailure(hr, "failed to create error code,subcode string while installing web error");

            // We don't care where it is, just whether it's there or not
            hr = MultiSzFindSubstring(pwzAcceptableErrors, pwzAcceptableCodeSubCode, NULL, NULL);
            ExitOnFailure1(hr, "failed to find whether or not error code, subcode: %ls is supported", pwzCodeSubCode);

            if (S_FALSE == hr)
            {
                WcaLog(LOGMSG_VERBOSE, "Skipping error code, subcode: %ls because it is not supported by the server.", pwzCodeSubCode);
                continue;
            }

            // If we didn't find it (and its an acceptable error) then we have nothing to replace
            fOldValueFound = FALSE;
        }

        // Set up the new error string if needed
        if (*(pswe->wzFile))
        {
            hr = StrAllocFormatted(&pwzNewError, L"%s,FILE,%s", pwzCodeSubCode, pswe->wzFile);
            ExitOnFailure2(hr, "failed to create new error code string with code,subcode: %ls, file: %ls", pwzCodeSubCode, pswe->wzFile);
        }
        else if (*(pswe->wzURL))
        {
            hr = StrAllocFormatted(&pwzNewError, L"%s,URL,%s", pwzCodeSubCode, pswe->wzURL);
            ExitOnFailure2(hr, "failed to create new error code string with code,subcode: %ls, file: %ls", pwzCodeSubCode, pswe->wzFile);
        }
        else if (fOldValueFound)
        {
            // If no File or URL was specified, they want a default error so remove the old value from the MULTISZ and move on
            hr = MultiSzRemoveString(&pwzErrors, dwFoundCodeSubCodeIndex);
            ExitOnFailure1(hr, "failed to remove string for error code sub code: %ls in order to make it 'default'", pwzCodeSubCode);
            continue;
        }

        // If we have something to replace, replace it, otherwise, put it at the beginning (order shouldn't matter)
        if (fOldValueFound)
        {
            hr = MultiSzReplaceString(&pwzErrors, dwFoundCodeSubCodeIndex, pwzNewError);
            ExitOnFailure1(hr, "failed to replace old error string with new error string for error code,subcode: %ls", pwzCodeSubCode);
        }
        else
        {
            hr = MultiSzPrepend(&pwzErrors, NULL, pwzNewError);
            ExitOnFailure1(hr, "failed to prepend new error string for error code,subcode: %ls", pwzCodeSubCode);
        }
    }

    // now write the CustomErrors to the metabase
    if (weptWeb == iParentType)
    {
        hr = ScaWriteMetabaseValue(piMetabase, wzRoot, L"/Root", MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, pwzErrors);
        ExitOnFailure(hr, "Failed to write Web Error to /Root");
    }
    else
    {
        hr = ScaWriteMetabaseValue(piMetabase, wzRoot, NULL, MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, pwzErrors);
        ExitOnFailure(hr, "Failed to write Web Error");
    }

LExit:
    ReleaseStr(pwzErrors);
    ReleaseStr(pwzSearchKey);
    ReleaseStr(pwzCodeSubCode);
    ReleaseStr(pwzAcceptableCodeSubCode);
    ReleaseStr(pwzAcceptableErrors);

    return hr;
}