HRESULT ScaDbsInstall( __in SCA_DB* psdList ) { HRESULT hr = S_FALSE; // assume nothing will be done SCA_DB* psd = NULL; for (psd = psdList; psd; psd = psd->psdNext) { if (psd->fHasComponent) { // if we need to drop, do that first if (((psd->iAttributes & SCADB_DROP_ON_INSTALL) && WcaIsInstalling(psd->isInstalled, psd->isAction) && !WcaIsReInstalling(psd->isInstalled, psd->isAction)) || ((psd->iAttributes & SCADB_DROP_ON_REINSTALL) && WcaIsReInstalling(psd->isInstalled, psd->isAction))) { hr = SchedDropDatabase(psd->wzKey, psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->iAttributes, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword); ExitOnFailure1(hr, "Failed to drop database %ls", psd->wzKey); } // if installing this component if (((psd->iAttributes & SCADB_CREATE_ON_INSTALL) && WcaIsInstalling(psd->isInstalled, psd->isAction) && !WcaIsReInstalling(psd->isInstalled, psd->isAction)) || ((psd->iAttributes & SCADB_CREATE_ON_REINSTALL) && WcaIsReInstalling(psd->isInstalled, psd->isAction))) { hr = SchedCreateDatabase(psd); ExitOnFailure1(hr, "Failed to ensure database %ls exists", psd->wzKey); } } } LExit: return hr; }
HRESULT ScaFiltersInstall7( __in SCA_FILTER* psfList ) { HRESULT hr = S_OK; SCA_FILTER* psf = psfList; if (!psf) { ExitFunction(); } //write global filters hr = ScaWriteConfigID(IIS_FILTER_GLOBAL_BEGIN); ExitOnFailure(hr, "Failed to write filter begin ID"); while (psf) { if (WcaIsInstalling(psf->isInstalled, psf->isAction)) { if (0 == wcscmp(psf->wzFilterRoot, L"/")) { hr = WriteFilter(psf); } } psf = psf->psfNext; } hr = ScaWriteConfigID(IIS_FILTER_END); ExitOnFailure(hr, "Failed to write filter ID"); psf = psfList; //Write Web Site Filters hr = ScaWriteConfigID(IIS_FILTER_BEGIN); ExitOnFailure(hr, "Failed to write filter begin ID"); while (psf) { if (WcaIsInstalling(psf->isInstalled, psf->isAction)) { if (0 != wcscmp(psf->wzFilterRoot, L"/")) { hr = WriteFilter(psf); } } psf = psf->psfNext; } hr = ScaWriteConfigID(IIS_FILTER_END); ExitOnFailure(hr, "Failed to write filter ID"); LExit: return hr; }
HRESULT MqiMessageQueuePermissionInstall( MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; // add count to action data hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData); ExitOnFailure(hr, "Failed to add count to custom action data"); for (MQI_MESSAGE_QUEUE_PERMISSION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // queue permissions that are being installed only if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) continue; // add message queue permission to action data hr = AddMessageQueuePermissionToActionData(pItm, ppwzActionData); ExitOnFailure(hr, "Failed to add message queue permission to action data"); } hr = S_OK; LExit: return hr; }
/******************************************************************** WcaGetComponentToDo() - gets a component's install states and determines if they mean install, uninstall, or reinstall. ********************************************************************/ extern "C" WCA_TODO WIXAPI WcaGetComponentToDo( __in_z LPCWSTR wzComponentId ) { INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; if (ERROR_SUCCESS != ::MsiGetComponentStateW(WcaGetInstallHandle(), wzComponentId, &isInstalled, &isAction)) { return WCA_TODO_UNKNOWN; } if (WcaIsReInstalling(isInstalled, isAction)) { return WCA_TODO_REINSTALL; } else if (WcaIsUninstalling(isInstalled, isAction)) { return WCA_TODO_UNINSTALL; } else if (WcaIsInstalling(isInstalled, isAction)) { return WCA_TODO_INSTALL; } else { return WCA_TODO_UNKNOWN; } }
HRESULT MqiMessageQueueInstall( MQI_MESSAGE_QUEUE_LIST* pList, BOOL fRollback, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; // add count to action data hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData); ExitOnFailure(hr, "Failed to add count to custom action data"); for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // queues that are being installed only if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) continue; // if the queue exists we should not try to create it if (pItm->fExists && !fRollback) { continue; } // add message queue to action data hr = AddMessageQueueToActionData(pItm, ppwzActionData); ExitOnFailure(hr, "Failed to add message queue to action data"); } hr = S_OK; LExit: return hr; }
BOOL CpiWillBeInstalled( INSTALLSTATE isInstalled, INSTALLSTATE isAction ) { return WcaIsInstalling(isInstalled, isAction) || (CpiIsInstalled(isInstalled) && !WcaIsUninstalling(isInstalled, isAction)); }
HRESULT CpiPartitionUsersInstall( CPI_PARTITION_USER_LIST* pList, int iRunMode, LPWSTR* ppwzActionData, int* piProgress ) { HRESULT hr = S_OK; int iActionType; // add action text hr = CpiAddActionTextToActionData(L"AddComPlusPartitionUsers", ppwzActionData); ExitOnFailure(hr, "Failed to add action text to custom action data"); // add partition count to action data hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData); ExitOnFailure(hr, "Failed to add count to custom action data"); // add applications to custom action data for (CPI_PARTITION_USER* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // partitions that are being installed only if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) continue; // action type if (rmRollback == iRunMode) { if (CpiIsInstalled(pItm->isInstalled)) iActionType = atNoOp; else iActionType = atRemove; } else iActionType = atCreate; // add to action data hr = AddPartitionUserToActionData(pItm, iActionType, COST_PARTITION_USER_CREATE, ppwzActionData); ExitOnFailure(hr, "Failed to add partition user to custom action data, key: %S", pItm->wzKey); } // add progress tics if (piProgress) *piProgress += COST_PARTITION_USER_CREATE * pList->iInstallCount; hr = S_OK; LExit: return hr; }
HRESULT MqiMessageQueueVerify( MQI_MESSAGE_QUEUE_LIST* pList ) { HRESULT hr = S_OK; LPWSTR pwzFormatName = NULL; DWORD dwCount = 128; for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // queues that are being installed only if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) continue; // get format name hr = StrAlloc(&pwzFormatName, dwCount); ExitOnFailure(hr, "Failed to allocate format name string"); do { hr = gpfnMQPathNameToFormatName(pItm->wzPathName, pwzFormatName, &dwCount); switch (hr) { case MQ_ERROR_QUEUE_NOT_FOUND: break; // break case MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL: hr = StrAlloc(&pwzFormatName, dwCount); ExitOnFailure(hr, "Failed to reallocate format name string"); hr = S_FALSE; // retry break; default: ExitOnFailure(hr, "Failed to get format name"); hr = S_OK; } } while (S_FALSE == hr); if (MQ_ERROR_QUEUE_NOT_FOUND == hr) { continue; } pItm->fExists = TRUE; pList->iInstallCount--; // clean up ReleaseNullStr(pwzFormatName); } hr = S_OK; LExit: ReleaseStr(pwzFormatName); return hr; }
HRESULT ScaWebDirsInstall(IMSAdminBase* piMetabase, SCA_WEBDIR* pswdList, SCA_APPPOOL * psapList) { HRESULT hr = S_OK; SCA_WEBDIR* pswd = pswdList; int i; while (pswd) { // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created if (WcaIsReInstalling(pswd->isInstalled, pswd->isAction)) { if (pswd->fHasApplication) { hr = ScaDeleteApp(piMetabase, pswd->wzWebDirRoot); ExitOnFailure(hr, "Failed to remove application for WebDir as part of a reinstall"); } } // if we are installing the web site if (WcaIsInstalling(pswd->isInstalled, pswd->isAction)) { hr = ScaCreateMetabaseKey(piMetabase, pswd->wzWebDirRoot, L""); ExitOnFailure(hr, "Failed to create key for WebDir"); hr = ScaWriteMetabaseValue(piMetabase, pswd->wzWebDirRoot, L"", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebDirectory"); ExitOnFailure(hr, "Failed to write key type for for WebDir"); i = 0x4000003e; // 1073741886: default directory browsing rights hr = ScaWriteMetabaseValue(piMetabase, pswd->wzWebDirRoot, L"", MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)i)); ExitOnFailure(hr, "Failed to set directory browsing for WebDir"); // get the security information for this web if (pswd->fHasProperties) { ScaWriteWebDirProperties(piMetabase, pswd->wzWebDirRoot, &pswd->swp); ExitOnFailure(hr, "Failed to write properties for WebDir"); } // get the application information for this web directory if (pswd->fHasApplication) { hr = ScaWriteWebApplication(piMetabase, pswd->wzWebDirRoot, &pswd->swapp, psapList); ExitOnFailure(hr, "Failed to write application for WebDir"); } } pswd = pswd->pswdNext; } LExit: return hr; }
HRESULT ScaFiltersInstall(IMSAdminBase* piMetabase, SCA_FILTER* psfList) { HRESULT hr = S_OK; SCA_FILTER* psf = psfList; while (psf) { if (WcaIsInstalling(psf->isInstalled, psf->isAction)) { hr = ScaCreateMetabaseKey(piMetabase, psf->wzFilterRoot, psf->wzKey); ExitOnFailure1(hr, "Failed to create key for filter '%S'", psf->wzKey); hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsFilter"); ExitOnFailure1(hr, "Failed to write key type for filter '%S'", psf->wzKey); // filter path hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)psf->wzPath); ExitOnFailure1(hr, "Failed to write Path for filter '%S'", psf->wzKey); // filter description hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_DESCRIPTION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)psf->wzDescription); ExitOnFailure1(hr, "Failed to write Description for filter ''%S", psf->wzKey); // filter flags if (MSI_NULL_INTEGER != psf->iFlags) { hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psf->iFlags)); ExitOnFailure1(hr, "Failed to write Flags for filter '%S'", psf->wzKey); } // filter load order if (MSI_NULL_INTEGER != psf->iLoadOrder) { hr = ScaAddFilterToLoadOrder(piMetabase, psf->wzFilterRoot, psf->wzKey, psf->iLoadOrder); ExitOnFailure1(hr, "Failed to add filter '%S' to load order", psf->wzKey); } } psf = psf->psfNext; } LExit: return hr; }
HRESULT ScaPropertyInstall( IMSAdminBase* piMetabase, SCA_PROPERTY* pspList ) { Assert(piMetabase); HRESULT hr = S_OK; for (SCA_PROPERTY* psp = pspList; psp; psp = psp->pspNext) { // if we are installing the web site if (WcaIsInstalling(psp->isInstalled, psp->isAction)) { hr = ScaWriteProperty(piMetabase, psp); ExitOnFailure1(hr, "failed to write Property '%ls' to metabase", psp->wzProperty); } } LExit: return hr; }
HRESULT ScaSqlStrsReadScripts( __inout SCA_SQLSTR** ppsssList, __in SCA_ACTION saAction ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; PMSIHANDLE hViewBinary, hRecBinary; PMSIHANDLE hViewUser, hRecUser; LPWSTR pwzComponent = NULL; LPWSTR pwzData = NULL; BYTE* pbScript = NULL; DWORD cbRead = 0; DWORD cbScript = 0; DWORD cchScript = 0; LPWSTR pwzScriptBuffer = NULL; WCHAR* pwzScript = NULL; WCHAR* pwz; DWORD cch = 0; SCA_SQLSTR sss; SCA_SQLSTR* psss = NULL; if (S_OK != WcaTableExists(L"SqlScript") || S_OK != WcaTableExists(L"SqlDatabase") || S_OK != WcaTableExists(L"Binary")) { WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsReadScripts() - SqlScripts and/or SqlDatabase table not present"); ExitFunction1(hr = S_FALSE); } // open a view on the binary table hr = WcaOpenView(vcsSqlBinaryScriptQuery, &hViewBinary); ExitOnFailure(hr, "Failed to open view on Binary table for SqlScripts"); // loop through all the sql scripts hr = WcaOpenExecuteView(vcsSqlScriptQuery, &hView); ExitOnFailure(hr, "Failed to open view on SqlScript table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; hr = WcaGetRecordString(hRec, sscrqComponent, &pwzComponent); ExitOnFailure(hr, "Failed to get Component for SQL Script."); er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction); hr = HRESULT_FROM_WIN32(er); ExitOnFailure1(hr, "Failed to get state for component: %ls", pwzComponent); // If we're doing install but the Component is not being installed or we're doing // uninstall but the Component is not being uninstalled, skip it. if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) || (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction)) { continue; } ::ZeroMemory(&sss, sizeof(sss)); sss.isInstalled = isInstalled; sss.isAction = isAction; hr = WcaGetRecordString(hRec, sscrqSqlScript, &pwzData); ExitOnFailure(hr, "Failed to get SqlScript.Script"); hr = ::StringCchCopyW(sss.wzKey, countof(sss.wzKey), pwzData); ExitOnFailure1(hr, "Failed to copy SqlScript.Script: %ls", pwzData); // find the database information for this string hr = WcaGetRecordString(hRec, sscrqSqlDb, &pwzData); ExitOnFailure1(hr, "Failed to get SqlScript.SqlDb_ for SqlScript '%ls'", sss.wzKey); hr = ::StringCchCopyW(sss.wzSqlDb, countof(sss.wzSqlDb), pwzData); ExitOnFailure1(hr, "Failed to copy SqlScritp.SqlDbb: %ls", pwzData); hr = WcaGetRecordInteger(hRec, sscrqAttributes, &sss.iAttributes); ExitOnFailure1(hr, "Failed to get SqlScript.Attributes for SqlScript '%ls'", sss.wzKey); hr = WcaGetRecordInteger(hRec, sscrqSequence, &sss.iSequence); ExitOnFailure1(hr, "Failed to get SqlScript.Sequence for SqlScript '%ls'", sss.wzKey); // get the sql script out of the binary stream hr = WcaExecuteView(hViewBinary, hRec); ExitOnFailure1(hr, "Failed to open SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey); hr = WcaFetchSingleRecord(hViewBinary, &hRecBinary); ExitOnFailure1(hr, "Failed to fetch SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey); // Note: We need to allocate an extra character on the stream to NULL terminate the SQL script. // The WcaGetRecordStream() function won't let us add extra space on the end of the stream // so we'll read the stream "the old fashioned way". //hr = WcaGetRecordStream(hRecBinary, ssbsqData, (BYTE**)&pbScript, &cbScript); //ExitOnFailure1(hr, "Failed to read SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey); er = ::MsiRecordReadStream(hRecBinary, ssbsqData, NULL, &cbRead); hr = HRESULT_FROM_WIN32(er); ExitOnFailure(hr, "failed to get size of stream"); cbScript = cbRead + sizeof(WCHAR); // we may have an ANSI SQL script but leave enough to even NULL terminate a WCHAR string hr = WcaAllocStream(&pbScript, cbScript); // this will allocate a fully zeroed out buffer so our string will be NULL terminated ExitOnFailure(hr, "failed to allocate data for stream"); er = ::MsiRecordReadStream(hRecBinary, ssbsqData, reinterpret_cast<char*>(pbScript), &cbRead); //read the buffer but leave the space for the NULL terminator hr = HRESULT_FROM_WIN32(er); ExitOnFailure(hr, "failed to read from stream"); Assert(cbRead + sizeof(WCHAR) == cbScript); // Check for the UNICODE BOM file marker. if ((0xFF == *pbScript) && (0xFE == *(pbScript + 1))) { // Copy the UNICODE string after the BOM marker (subtract one because we'll skip the BOM marker). cchScript = (cbScript / sizeof(WCHAR)) - 1; hr = StrAllocString(&pwzScriptBuffer, reinterpret_cast<LPWSTR>(pbScript) + 1, 0); ExitOnFailure1(hr, "Failed to allocate WCHAR string of size '%d'", cchScript); } else { // We have an ANSI string so convert it to UNICODE. cchScript = cbScript; hr = StrAllocStringAnsi(&pwzScriptBuffer, reinterpret_cast<LPCSTR>(pbScript), 0, CP_ACP); ExitOnFailure1(hr, "Failed to allocate WCHAR string of size '%d'", cchScript); } // Free the byte buffer since it has been converted to a new UNICODE string, one way or another. if (pbScript) { WcaFreeStream(pbScript); pbScript = NULL; } // Process the SQL script stripping out unnecessary stuff (like comments) and looking for "GO" statements. pwzScript = pwzScriptBuffer; while (cchScript && pwzScript && *pwzScript) { // strip off leading whitespace while (cchScript && *pwzScript && iswspace(*pwzScript)) { ++pwzScript; --cchScript; } Assert(0 <= cchScript); // if there is a SQL comment remove it while (cchScript && L'/' == *pwzScript && L'*' == *(pwzScript + 1)) { // go until end of comment while (cchScript && *pwzScript && *(pwzScript + 1) && !(L'*' == *pwzScript && L'/' == *(pwzScript + 1))) { ++pwzScript; --cchScript; } Assert(2 <= cchScript); if (2 <= cchScript) { // to account for */ at end pwzScript+=2; cchScript-=2; } Assert(0 <= cchScript); // strip off any new leading whitespace while (cchScript && *pwzScript && iswspace(*pwzScript)) { ++pwzScript; --cchScript; } } while (cchScript && L'-' == *pwzScript && L'-' == *(pwzScript + 1)) { // go past the new line character while (cchScript && *pwzScript && L'\n' != *pwzScript) { ++pwzScript; --cchScript; } Assert(0 <= cchScript); if (cchScript && L'\n' == *pwzScript) { ++pwzScript; --cchScript; } Assert(0 <= cchScript); // strip off any new leading whitespace while (cchScript && *pwzScript && iswspace(*pwzScript)) { ++pwzScript; --cchScript; } } Assert(0 <= cchScript); // try to isolate a "GO" keyword and count the characters in the SQL string pwz = pwzScript; cch = 0; while (cchScript && *pwz) { //skip past comment lines that might have "go" in them //note that these comments are "in the middle" of our function, //or possibly at the end of a line if (cchScript && L'-' == *pwz && L'-' == *(pwz + 1)) { // skip past chars until the new line character while (cchScript && *pwz && (L'\n' != *pwz)) { ++pwz; ++cch; --cchScript; } } //skip past comment lines of form /* to */ that might have "go" in them //note that these comments are "in the middle" of our function, //or possibly at the end of a line if (cchScript && L'/' == *pwz && L'*' == *(pwz + 1)) { // skip past chars until the new line character while (cchScript && *pwz && *(pwz + 1) && !((L'*' == *pwz) && (L'/' == *(pwz + 1)))) { ++pwz; ++cch; --cchScript; } if (2 <= cchScript) { // to account for */ at end pwz+=2; cch+=2; cchScript-=2; } } // Skip past strings that may be part of the SQL statement that might have a "go" in them if ( cchScript && L'\'' == *pwz ) { ++pwz; ++cch; --cchScript; // Skip past chars until the end of the string while ( cchScript && *pwz && !(L'\'' == *pwz) ) { ++pwz; ++cch; --cchScript; } } // Skip past strings that may be part of the SQL statement that might have a "go" in them if ( cchScript && L'\"' == *pwz ) { ++pwz; ++cch; --cchScript; // Skip past chars until the end of the string while ( cchScript && *pwz && !(L'\"' == *pwz) ) { ++pwz; ++cch; --cchScript; } } // if "GO" is isolated if ((pwzScript == pwz || iswspace(*(pwz - 1))) && (L'G' == *pwz || L'g' == *pwz) && (L'O' == *(pwz + 1) || L'o' == *(pwz + 1)) && (0 == *(pwz + 2) || iswspace(*(pwz + 2)))) { *pwz = 0; // null terminate the SQL string on the "G" pwz += 2; cchScript -= 2; break; // found "GO" now add SQL string to list } ++pwz; ++cch; --cchScript; } Assert(0 <= cchScript); if (0 < cch) //don't process if there's nothing to process { // replace tabs with spaces for (LPWSTR pwzTab = wcsstr(pwzScript, L"\t"); pwzTab; pwzTab = wcsstr(pwzTab, L"\t")) *pwzTab = ' '; // strip off whitespace at the end of the script string for (LPWSTR pwzErase = pwzScript + cch - 1; pwzScript < pwzErase && iswspace(*pwzErase); pwzErase--) { *(pwzErase) = 0; cch--; } } if (0 < cch) { hr = NewSqlStr(&psss); ExitOnFailure(hr, "failed to allocate new sql string element"); // copy everything over hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), sss.wzKey); ExitOnFailure(hr, "Failed to copy key string to sqlstr object"); hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), sss.wzSqlDb); ExitOnFailure(hr, "Failed to copy DB string to sqlstr object"); hr = ::StringCchCopyW(psss->wzComponent, countof(psss->wzComponent), sss.wzComponent); ExitOnFailure(hr, "Failed to copy component string to sqlstr object"); psss->isInstalled = sss.isInstalled; psss->isAction = sss.isAction; psss->iAttributes = sss.iAttributes; psss->iSequence = sss.iSequence; // cchRequired includes the NULL terminating char hr = StrAllocString(&psss->pwzSql, pwzScript, 0); ExitOnFailure1(hr, "Failed to allocate string for SQL script: '%ls'", psss->wzKey); *ppsssList = AddSqlStrToList(*ppsssList, psss); psss = NULL; // set the db NULL so it doesn't accidentally get freed below } pwzScript = pwz; } } if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "Failure occured while reading SqlString table"); LExit: // if anything was left over after an error clean it all up if (psss) { ScaSqlStrsFreeList(psss); } if (pbScript) { WcaFreeStream(pbScript); } ReleaseStr(pwzScriptBuffer); ReleaseStr(pwzData); ReleaseStr(pwzComponent); return hr; }
static HRESULT TrusteesInApplicationRolesRead( LPCWSTR pwzQuery, CPI_APPLICATION_ROLE_LIST* pAppRoleList, CPI_USER_IN_APPLICATION_ROLE_LIST* pUsrInAppRoleList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; CPI_USER_IN_APPLICATION_ROLE* pItm = NULL; LPWSTR pwzData = NULL; LPWSTR pwzDomain = NULL; LPWSTR pwzName = NULL; BOOL fMatchingArchitecture = FALSE; // loop through all application roles hr = WcaOpenExecuteView(pwzQuery, &hView); ExitOnFailure(hr, "Failed to execute view on table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // get component hr = WcaGetRecordString(hRec, tiarqComponent, &pwzData); ExitOnFailure(hr, "Failed to get component"); // check if the component is our processor architecture hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); ExitOnFailure(hr, "Failed to get component architecture."); if (!fMatchingArchitecture) { continue; // not the same architecture, ignore } // create entry pItm = (CPI_USER_IN_APPLICATION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_USER_IN_APPLICATION_ROLE)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); // get component install state er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); // get key hr = WcaGetRecordString(hRec, tiarqUserInApplicationRole, &pwzData); ExitOnFailure(hr, "Failed to get key"); StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); // get application role hr = WcaGetRecordString(hRec, tiarqApplicationRole, &pwzData); ExitOnFailure(hr, "Failed to get application role"); hr = CpiApplicationRoleFindByKey(pAppRoleList, pwzData, &pItm->pApplicationRole); if (S_FALSE == hr) hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); ExitOnFailure1(hr, "Failed to find application role, key: %S", pwzData); // get user domain hr = WcaGetRecordFormattedString(hRec, tiarqDomain, &pwzDomain); ExitOnFailure(hr, "Failed to get domain"); // get user name hr = WcaGetRecordFormattedString(hRec, tiarqName, &pwzName); ExitOnFailure(hr, "Failed to get name"); // build account name hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount); ExitOnFailure(hr, "Failed to build account name"); // set references & increment counters if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) { CpiApplicationRoleAddReferenceInstall(pItm->pApplicationRole); pUsrInAppRoleList->iInstallCount++; } if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) { CpiApplicationRoleAddReferenceUninstall(pItm->pApplicationRole); pUsrInAppRoleList->iUninstallCount++; } // add entry if (pUsrInAppRoleList->pFirst) pItm->pNext = pUsrInAppRoleList->pFirst; pUsrInAppRoleList->pFirst = pItm; pItm = NULL; } if (E_NOMOREITEMS == hr) hr = S_OK; LExit: // clean up if (pItm) FreeUserInApplicationRole(pItm); ReleaseStr(pwzData); ReleaseStr(pwzDomain); ReleaseStr(pwzName); return hr; }
HRESULT ScaSqlStrsRead( __inout SCA_SQLSTR** ppsssList, __in SCA_ACTION saAction ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; PMSIHANDLE hViewUser, hRecUser; LPWSTR pwzComponent = NULL; LPWSTR pwzData = NULL; SCA_SQLSTR* psss = NULL; if (S_OK != WcaTableExists(L"SqlString") || S_OK != WcaTableExists(L"SqlDatabase")) { WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsRead() - SqlString and/or SqlDatabase table not present"); ExitFunction1(hr = S_FALSE); } // loop through all the sql strings hr = WcaOpenExecuteView(vcsSqlStringQuery, &hView); ExitOnFailure(hr, "Failed to open view on SqlString table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; hr = WcaGetRecordString(hRec, ssqComponent, &pwzComponent); ExitOnFailure(hr, "Failed to get Component for SQL String."); er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction); hr = HRESULT_FROM_WIN32(er); ExitOnFailure1(hr, "Failed to get state for component: %ls", pwzComponent); // If we're doing install but the Component is not being installed or we're doing // uninstall but the Component is not being uninstalled, skip it. if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) || (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction)) { continue; } hr = NewSqlStr(&psss); ExitOnFailure(hr, "failed to allocation new sql string element"); psss->isInstalled = isInstalled; psss->isAction = isAction; hr = WcaGetRecordString(hRec, ssqSqlString, &pwzData); ExitOnFailure(hr, "Failed to get SqlString.String"); hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), pwzData); ExitOnFailure1(hr, "Failed to copy SqlString.String: %ls", pwzData); // find the database information for this string hr = WcaGetRecordString(hRec, ssqSqlDb, &pwzData); ExitOnFailure1(hr, "Failed to get SqlString.SqlDb_ for SqlString '%ls'", psss->wzKey); hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), pwzData); ExitOnFailure1(hr, "Failed to copy SqlString.SqlDb_: %ls", pwzData); hr = WcaGetRecordInteger(hRec, ssqAttributes, &psss->iAttributes); ExitOnFailure1(hr, "Failed to get SqlString.Attributes for SqlString '%ls'", psss->wzKey); //get the sequence number for the string (note that this will be sequenced with scripts too) hr = WcaGetRecordInteger(hRec, ssqSequence, &psss->iSequence); ExitOnFailure1(hr, "Failed to get SqlString.Sequence for SqlString '%ls'", psss->wzKey); // execute SQL hr = WcaGetRecordFormattedString(hRec, ssqSQL, &pwzData); ExitOnFailure1(hr, "Failed to get SqlString.SQL for SqlString '%ls'", psss->wzKey); Assert(!psss->pwzSql); hr = StrAllocString(&psss->pwzSql, pwzData, 0); ExitOnFailure1(hr, "Failed to alloc string for SqlString '%ls'", psss->wzKey); *ppsssList = AddSqlStrToList(*ppsssList, psss); psss = NULL; // set the sss to NULL so it doesn't get freed below } if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "Failure occured while reading SqlString table"); LExit: // if anything was left over after an error clean it all up if (psss) { ScaSqlStrsFreeList(psss); } ReleaseStr(pwzData); ReleaseStr(pwzComponent); return hr; }
HRESULT CpiPartitionsRead( CPI_PARTITION_LIST* pPartList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; CPI_PARTITION* pItm = NULL; LPWSTR pwzData = NULL; BOOL fMatchingArchitecture = FALSE; // loop through all partitions hr = WcaOpenExecuteView(vcsPartitionQuery, &hView); ExitOnFailure(hr, "Failed to execute view on ComPlusPartition table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // get component hr = WcaGetRecordString(hRec, pqComponent, &pwzData); ExitOnFailure(hr, "Failed to get component"); // check if the component is our processor architecture if (pwzData && *pwzData) { hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); ExitOnFailure(hr, "Failed to get component architecture."); if (!fMatchingArchitecture) { continue; // not the same architecture, ignore } } // create entry pItm = (CPI_PARTITION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); // get component install state if (pwzData && *pwzData) { pItm->fHasComponent = TRUE; er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); } // get key hr = WcaGetRecordString(hRec, pqPartition, &pwzData); ExitOnFailure(hr, "Failed to get key"); StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); // get id hr = WcaGetRecordFormattedString(hRec, pqID, &pwzData); ExitOnFailure(hr, "Failed to get id"); if (pwzData && *pwzData) { hr = PcaGuidToRegFormat(pwzData, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to parse id guid value, key: %S, value: '%S'", pItm->wzKey, pwzData); } // get name hr = WcaGetRecordFormattedString(hRec, pqName, &pwzData); ExitOnFailure(hr, "Failed to get name"); StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); // if partition is a locater, either an id or a name must be provided if (!pItm->fHasComponent && !*pItm->wzID && !*pItm->wzName) ExitOnFailure(hr = E_FAIL, "A partition locater must have either an id or a name associated, key: %S", pItm->wzKey); // if partition is not a locater, an name must be provided if (pItm->fHasComponent && !*pItm->wzName) ExitOnFailure(hr = E_FAIL, "A partition must have a name associated, key: %S", pItm->wzKey); // get properties if (CpiTableExists(cptComPlusPartitionProperty) && pItm->fHasComponent) { hr = CpiPropertiesRead(vcsPartitionPropertyQuery, pItm->wzKey, pdlPartitionProperties, &pItm->pProperties, &pItm->iPropertyCount); ExitOnFailure(hr, "Failed to get properties"); } // increment counters if (pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction)) pPartList->iInstallCount++; if (pItm->fHasComponent && WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) pPartList->iUninstallCount++; // add entry if (pPartList->pFirst) pItm->pNext = pPartList->pFirst; pPartList->pFirst = pItm; pItm = NULL; } if (E_NOMOREITEMS == hr) hr = S_OK; LExit: // clean up if (pItm) FreePartition(pItm); ReleaseStr(pwzData); return hr; }
HRESULT CpiPartitionsVerifyInstall( CPI_PARTITION_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogCollection* piPartColl = NULL; ICatalogObject* piPartObj = NULL; for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // referenced locaters or partitions that are being installed if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))) continue; // if the partition is referensed and is not a locater, it must be installed if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) MessageExitOnFailure(hr = E_FAIL, msierrComPlusPartitionDependency, "A partition is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); // get partitions collection if (!piPartColl) { hr = CpiGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); } // partition is supposed to exist if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled)) { // get collection object for partition hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); // if the partition was found if (S_OK == hr) { // if we don't have an id, copy id from object if (!*pItm->wzID) { hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } } // if the partition was not found else { // if the application is a locater, this is an error if (!pItm->fHasComponent) MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusPartitionNotFound, "A partition required by this installation was not found, key: %S", pItm->wzKey); // create a new id if one is missing if (!*pItm->wzID) { hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } } // partition is supposed to be created else { // check for conflicts do { if (*pItm->wzID) { // find partitions with conflicting id hr = CpiFindCollectionObject(piPartColl, pItm->wzID, NULL, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); if (S_FALSE == hr) { // find partitions with conflicting name hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); if (S_OK == hr) // "A partition with a conflictiong name exists. retry cancel" er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0); else break; // no conflicting entry found, break loop } else // "A partition with a conflicting id exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusPartitionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); } else { // find partitions with conflicting name hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); if (S_OK == hr) // "A partition with a conflictiong name exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); else break; // no conflicting entry found, break loop } switch (er) { case IDCANCEL: case IDABORT: ExitOnFailure(hr = E_FAIL, "A partition with a conflictiong name or id exists, key: %S", pItm->wzKey); break; case IDRETRY: break; case IDIGNORE: default: // if we don't have an id, copy id from object if (!*pItm->wzID) { hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } hr = S_FALSE; // indicate that this is not a conflict } } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts // create a new id if one is missing if (!*pItm->wzID) { hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } // clean up ReleaseNullObject(piPartObj); } hr = S_OK; LExit: // clean up ReleaseObject(piPartColl); ReleaseObject(piPartObj); return hr; }
HRESULT CpiPartitionUsersRead( CPI_PARTITION_LIST* pPartList, CPI_PARTITION_USER_LIST* pPartUsrList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; CPI_PARTITION_USER* pItm = NULL; LPWSTR pwzData = NULL; LPWSTR pwzDomain = NULL; LPWSTR pwzName = NULL; BOOL fMatchingArchitecture = FALSE; // loop through all partition users hr = WcaOpenExecuteView(vcsPartitionUserQuery, &hView); ExitOnFailure(hr, "Failed to execute view on ComPlusPartitionUser table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // get component hr = WcaGetRecordString(hRec, puqComponent, &pwzData); ExitOnFailure(hr, "Failed to get component"); // check if the component is our processor architecture hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); ExitOnFailure(hr, "Failed to get component architecture."); if (!fMatchingArchitecture) { continue; // not the same architecture, ignore } // create entry pItm = (CPI_PARTITION_USER*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_PARTITION_USER)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); // get component install state er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); // get key hr = WcaGetRecordString(hRec, puqPartitionUser, &pwzData); ExitOnFailure(hr, "Failed to get key"); StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); // get partition hr = WcaGetRecordString(hRec, puqPartition, &pwzData); ExitOnFailure(hr, "Failed to get partition"); hr = CpiPartitionFindByKey(pPartList, pwzData, &pItm->pPartition); if (S_FALSE == hr) hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); ExitOnFailure(hr, "Failed to find partition, key: %S", pwzData); // get user domain hr = WcaGetRecordFormattedString(hRec, puqDomain, &pwzDomain); ExitOnFailure(hr, "Failed to get user domain"); // get user name hr = WcaGetRecordFormattedString(hRec, puqName, &pwzName); ExitOnFailure(hr, "Failed to get user name"); // build account name hr = CpiBuildAccountName(pwzDomain, pwzName, &pItm->pwzAccount); ExitOnFailure(hr, "Failed to build account name"); // set references & increment counters if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) { pItm->pPartition->fReferencedForInstall = TRUE; pPartUsrList->iInstallCount++; } if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) { pItm->pPartition->fReferencedForUninstall = TRUE; pPartUsrList->iUninstallCount++; } // add entry if (pPartUsrList->pFirst) pItm->pNext = pPartUsrList->pFirst; pPartUsrList->pFirst = pItm; pItm = NULL; } if (E_NOMOREITEMS == hr) hr = S_OK; LExit: // clean up if (pItm) FreePartitionUser(pItm); ReleaseStr(pwzData); ReleaseStr(pwzDomain); ReleaseStr(pwzName); return hr; }
HRESULT ScaWebsRead( __in IMSAdminBase* piMetabase, __in SCA_MIMEMAP** ppsmmList, __in SCA_WEB** ppswList, __in SCA_HTTP_HEADER** ppshhList, __in SCA_WEB_ERROR** ppsweList, __in WCA_WRAPQUERY_HANDLE hUserQuery, __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, __in WCA_WRAPQUERY_HANDLE hSslCertQuery, __in WCA_WRAPQUERY_HANDLE hWebLogQuery, __in WCA_WRAPQUERY_HANDLE hWebAppQuery, __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, __inout LPWSTR *ppwzCustomActionData ) { Assert(piMetabase && ppswList); HRESULT hr = S_OK; MSIHANDLE hRec; MSIHANDLE hRecAddresses; SCA_WEB* psw = NULL; LPWSTR pwzData = NULL; int iSiteId; DWORD dwLen = 0; WCA_WRAPQUERY_HANDLE hQueryWebSite = NULL; WCA_WRAPQUERY_HANDLE hQueryWebAddress = NULL; hr = WcaBeginUnwrapQuery(&hQueryWebSite, ppwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead"); hr = WcaBeginUnwrapQuery(&hQueryWebAddress, ppwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead"); if (0 == WcaGetQueryRecords(hQueryWebSite)) { WcaLog(LOGMSG_VERBOSE, "Required tables not present"); ExitFunction1(hr = S_FALSE); } // loop through all the webs while (S_OK == (hr = WcaFetchWrappedRecord(hQueryWebSite, &hRec))) { psw = NewWeb(); ExitOnNull(psw, hr, E_OUTOFMEMORY, "Failed to allocate memory for web object in memory"); // get the darwin information hr = WcaGetRecordString(hRec, wqWeb, &pwzData); ExitOnFailure(hr, "Failed to get Web"); hr = ::StringCchCopyW(psw->wzKey, countof(psw->wzKey), pwzData); ExitOnFailure(hr, "Failed to copy key string to web object"); if (*pwzData && *ppsmmList) { hr = ScaGetMimeMap(mmptWeb, pwzData, ppsmmList, &psw->psmm); ExitOnFailure(hr, "Failed to get mimemap for VirtualDir"); } // get component install state hr = WcaGetRecordString(hRec, wqComponent, &pwzData); ExitOnFailure(hr, "Failed to get Component for Web"); hr = ::StringCchCopyW(psw->wzComponent, countof(psw->wzComponent), pwzData); ExitOnFailure(hr, "Failed to copy component string to web object"); if (*(psw->wzComponent)) { psw->fHasComponent = TRUE; hr = WcaGetRecordInteger(hRec, wqInstalled, (int *)&psw->isInstalled); ExitOnFailure(hr, "Failed to get web Component's installed state"); WcaGetRecordInteger(hRec, wqAction, (int *)&psw->isAction); ExitOnFailure(hr, "Failed to get web Component's action state"); if (!WcaIsInstalling(psw->isInstalled, psw->isAction) && !WcaIsUninstalling(psw->isInstalled, psw->isAction) && !WcaIsReInstalling(psw->isInstalled, psw->isAction)) { FreeWeb(psw); psw = NULL; continue; // If we aren't acting on this component, skip it } } hr = WcaGetRecordInteger(hRec, wqId, &iSiteId); ExitOnFailure(hr, "Failed to get SiteId for Web"); // Get the web's key address. hr = WcaGetRecordString(hRec, wqAddress, &pwzData); ExitOnFailure(hr, "Failed to get Address for Web"); hr = ::StringCchCopyW(psw->swaKey.wzKey, countof(psw->swaKey.wzKey), pwzData); ExitOnFailure(hr, "Failed to copy key string to web object"); hr = WcaGetRecordString(hRec, wqIP, &pwzData); ExitOnFailure(hr, "Failed to get IP for Web"); hr = ::StringCchCopyW(psw->swaKey.wzIP, countof(psw->swaKey.wzIP), pwzData); ExitOnFailure(hr, "Failed to copy IP string to web object"); hr = WcaGetRecordString(hRec, wqPort, &pwzData); ExitOnFailure(hr, "Failed to get Web Address port"); psw->swaKey.iPort = wcstol(pwzData, NULL, 10); hr = WcaGetRecordString(hRec, wqHeader, &pwzData); ExitOnFailure(hr, "Failed to get Header for Web"); hr = ::StringCchCopyW(psw->swaKey.wzHeader, countof(psw->swaKey.wzHeader), pwzData); ExitOnFailure(hr, "Failed to copy header string to web object"); hr = WcaGetRecordInteger(hRec, wqSecure, &psw->swaKey.fSecure); ExitOnFailure(hr, "Failed to get if Web is secure"); if (S_FALSE == hr) { psw->swaKey.fSecure = FALSE; } // Get the web's description. hr = WcaGetRecordString(hRec, wqDescription, &pwzData); ExitOnFailure(hr, "Failed to get Description for Web"); hr = ::StringCchCopyW(psw->wzDescription, countof(psw->wzDescription), pwzData); ExitOnFailure(hr, "Failed to copy description string to web object"); // Try to find the web root in case it already exists. dwLen = METADATA_MAX_NAME_LEN; hr = ScaWebFindBase(piMetabase, *ppswList, psw->wzKey, iSiteId, psw->swaKey.wzIP, psw->swaKey.iPort, psw->swaKey.wzHeader, psw->swaKey.fSecure, psw->wzDescription, psw->wzWebBase, dwLen); if (S_OK == hr) { psw->fBaseExists = TRUE; } else if (S_FALSE == hr) // didn't find the web site. { psw->fBaseExists = FALSE; // If we're actually configuring the web site. if (psw->fHasComponent) { if (WcaIsInstalling(psw->isInstalled, psw->isAction)) { hr = ScaWebFindFreeBase(piMetabase, *ppswList, iSiteId, psw->wzDescription, psw->wzWebBase, countof(psw->wzWebBase)); ExitOnFailure(hr, "Failed to find free web root."); } else if (WcaIsUninstalling(psw->isInstalled, psw->isAction)) { WcaLog(LOGMSG_VERBOSE, "Web site: '%ls' was already removed, skipping.", psw->wzKey); hr = S_OK; continue; } } } ExitOnFailure(hr, "Failed to find web root"); // get any extra web addresses WcaFetchWrappedReset(hQueryWebAddress); while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hQueryWebAddress, 2, psw->wzKey, &hRecAddresses))) { if (MAX_ADDRESSES_PER_WEB <= psw->cExtraAddresses) { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); ExitOnFailure(hr, "Failure to get more extra web addresses, max exceeded."); } hr = WcaGetRecordString(hRecAddresses, waqAddress, &pwzData); ExitOnFailure(hr, "Failed to get extra web Address"); // if this isn't the key address add it if (0 != lstrcmpW(pwzData, psw->swaKey.wzKey)) { hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey), pwzData); ExitOnFailure(hr, "Failed to copy extra addresses key string to web object"); hr = WcaGetRecordString(hRecAddresses, waqIP, &pwzData); ExitOnFailure(hr, "Failed to get extra web IP"); hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP), pwzData); ExitOnFailure(hr, "Failed to copy extra addresses IP string to web object"); hr = WcaGetRecordString(hRecAddresses, waqPort, &pwzData); ExitOnFailure(hr, "Failed to get port for extra web IP"); psw->swaExtraAddresses[psw->cExtraAddresses].iPort= wcstol(pwzData, NULL, 10); hr = WcaGetRecordString(hRecAddresses, waqHeader, &pwzData); ExitOnFailure(hr, "Failed to get header for extra web IP"); hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader), pwzData); ExitOnFailure(hr, "Failed to copy extra addresses header string to web object"); hr = WcaGetRecordInteger(hRecAddresses, waqSecure, &psw->swaExtraAddresses[psw->cExtraAddresses].fSecure); ExitOnFailure(hr, "Failed to get if secure extra web IP"); if (S_FALSE == hr) psw->swaExtraAddresses[psw->cExtraAddresses].fSecure = FALSE; ++psw->cExtraAddresses; } } if (E_NOMOREITEMS == hr) hr = S_OK; ExitOnFailure(hr, "Failure occured while getting extra web addresses"); hr = WcaGetRecordInteger(hRec, wqConnectionTimeout, &psw->iConnectionTimeout); ExitOnFailure(hr, "Failed to get connection timeout for Web"); if (psw->fHasComponent) // If we're installing it, it needs a dir { // get the web's directory if (INSTALLSTATE_SOURCE == psw->isAction) { hr = WcaGetRecordString(hRec, wqSourcePath, &pwzData); } else { hr = WcaGetRecordString(hRec, wqTargetPath, &pwzData); } ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory"); // remove trailing backslashes while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\') { pwzData[lstrlenW(pwzData)-1] = 0; } hr = ::StringCchCopyW(psw->wzDirectory, countof(psw->wzDirectory), pwzData); ExitOnFailure(hr, "Failed to copy directory string to web object"); } hr = WcaGetRecordInteger(hRec, wqState, &psw->iState); ExitOnFailure(hr, "Failed to get state for Web"); hr = WcaGetRecordInteger(hRec, wqAttributes, &psw->iAttributes); ExitOnFailure(hr, "Failed to get attributes for Web"); // get the dir properties for this web hr = WcaGetRecordString(hRec, wqProperties, &pwzData); ExitOnFailure(hr, "Failed to get directory property record for Web"); if (*pwzData) { hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &psw->swp); ExitOnFailure(hr, "Failed to get directory properties for Web"); psw->fHasProperties = TRUE; } // get the application information for this web hr = WcaGetRecordString(hRec, wqApplication, &pwzData); ExitOnFailure(hr, "Failed to get application identifier for Web"); if (*pwzData) { hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &psw->swapp); ExitOnFailure(hr, "Failed to get application for Web"); psw->fHasApplication = TRUE; } // get the SSL certificates hr = ScaSslCertificateRead(psw->wzKey, hSslCertQuery, &(psw->pswscList)); ExitOnFailure(hr, "Failed to get SSL Certificates."); // get the custom headers if (*ppshhList) { hr = ScaGetHttpHeader(hhptWeb, psw->wzKey, ppshhList, &(psw->pshhList)); ExitOnFailure(hr, "Failed to get Custom HTTP Headers"); } // get the errors if (*ppsweList) { hr = ScaGetWebError(weptWeb, psw->wzKey, ppsweList, &(psw->psweList)); ExitOnFailure(hr, "Failed to get Custom Errors"); } // get the log information for this web hr = WcaGetRecordString(hRec, wqLog, &pwzData); ExitOnFailure(hr, "Failed to get log identifier for Web"); if (*pwzData) { hr = ScaGetWebLog(piMetabase, pwzData, hWebLogQuery, &psw->swl); ExitOnFailure(hr, "Failed to get Log for Web."); psw->fHasLog = TRUE; } *ppswList = AddWebToList(*ppswList, psw); psw = NULL; // set the web NULL so it doesn't accidentally get freed below } if (E_NOMOREITEMS == hr) { hr = S_OK; } LExit: // if anything was left over after an error clean it all up WcaFinishUnwrapQuery(hQueryWebSite); WcaFinishUnwrapQuery(hQueryWebAddress); if (psw) { ScaWebsFreeList(psw); } ReleaseStr(pwzData); return hr; }
static HRESULT ExecuteStrings( __in SCA_DB* psdList, __in SCA_SQLSTR* psssList, __in BOOL fInstall ) { HRESULT hr = S_FALSE; // assume nothing will be done int iRollback = -1; int iOldRollback = iRollback; LPCWSTR wzOldDb = NULL; UINT uiCost = 0; WCHAR* pwzCustomActionData = NULL; WCHAR wzNumber[64]; // loop through all sql strings for (SCA_SQLSTR* psss = psssList; psss; psss = psss->psssNext) { // if installing this component if ((fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_INSTALL) && WcaIsInstalling(psss->isInstalled, psss->isAction) && !WcaIsReInstalling(psss->isInstalled, psss->isAction)) || (fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_REINSTALL) && WcaIsReInstalling(psss->isInstalled, psss->isAction)) || (!fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_UNINSTALL) && WcaIsUninstalling(psss->isInstalled, psss->isAction))) { // determine if this is a rollback scheduling or normal deferred scheduling if (psss->iAttributes & SCASQL_ROLLBACK) { iRollback = 1; } else { iRollback = 0; } // if we need to create a connection to a new server\database if (!wzOldDb || 0 != lstrcmpW(wzOldDb, psss->wzSqlDb) || iOldRollback != iRollback) { const SCA_DB* psd = ScaDbsFindDatabase(psss->wzSqlDb, psdList); if (!psd) { ExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "failed to find data for Database: %ls", psss->wzSqlDb); } if (-1 == iOldRollback) { iOldRollback = iRollback; } Assert(0 == iOldRollback || 1 == iOldRollback); // if there was custom action data before, schedule the action to write it if (pwzCustomActionData && *pwzCustomActionData) { Assert(pwzCustomActionData && *pwzCustomActionData && uiCost); hr = WcaDoDeferredAction(1 == iOldRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost); ExitOnFailure1(hr, "failed to schedule ExecuteSqlStrings action, rollback: %d", iOldRollback); iOldRollback = iRollback; *pwzCustomActionData = L'\0'; uiCost = 0; } Assert(!pwzCustomActionData || (pwzCustomActionData && 0 == *pwzCustomActionData) && 0 == uiCost); hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Server Database String to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Server to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Instance to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Database to CustomActionData for Database String: %ls", psd->wzKey); hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->iAttributes); ExitOnFailure(hr, "Failed to format attributes integer value to string"); hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Attributes to CustomActionData for Database String: %ls", psd->wzKey); hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->fUseIntegratedAuth); ExitOnFailure(hr, "Failed to format UseIntegratedAuth integer value to string"); hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL IntegratedAuth flag to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL UserName to CustomActionData for Database String: %ls", psd->wzKey); hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Password to CustomActionData for Database String: %ls", psd->wzKey); uiCost += COST_SQL_CONNECTDB; wzOldDb = psss->wzSqlDb; } WcaLog(LOGMSG_VERBOSE, "Scheduling SQL string: %ls", psss->pwzSql); hr = WcaWriteStringToCaData(psss->wzKey, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to add SQL Key to CustomActionData for SQL string: %ls", psss->wzKey); hr = WcaWriteIntegerToCaData(psss->iAttributes, &pwzCustomActionData); ExitOnFailure1(hr, "failed to add attributes to CustomActionData for SQL string: %ls", psss->wzKey); hr = WcaWriteStringToCaData(psss->pwzSql, &pwzCustomActionData); ExitOnFailure1(hr, "Failed to to add SQL Query to CustomActionData for SQL string: %ls", psss->wzKey); uiCost += COST_SQL_STRING; } } if (pwzCustomActionData && *pwzCustomActionData) { Assert(pwzCustomActionData && *pwzCustomActionData && uiCost); hr = WcaDoDeferredAction(1 == iRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost); ExitOnFailure(hr, "Failed to schedule ExecuteSqlStrings action"); *pwzCustomActionData = L'\0'; uiCost = 0; } LExit: ReleaseStr(pwzCustomActionData); return hr; }
HRESULT __stdcall ScaVirtualDirsRead( __in IMSAdminBase* piMetabase, __in SCA_WEB* pswList, __in SCA_VDIR** ppsvdList, __in SCA_MIMEMAP** ppsmmList, __in SCA_HTTP_HEADER** ppshhList, __in SCA_WEB_ERROR** ppsweList, __in WCA_WRAPQUERY_HANDLE hUserQuery, __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, __in WCA_WRAPQUERY_HANDLE hWebAppQuery, __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, __inout LPWSTR *ppwzCustomActionData ) { Assert(piMetabase && ppsvdList); HRESULT hr = S_OK; MSIHANDLE hRec; INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; SCA_VDIR* pvdir = NULL; LPWSTR pwzData = NULL; WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); if (0 == WcaGetQueryRecords(hWrapQuery)) { WcaLog(LOGMSG_VERBOSE, "Skipping ScaVirtualDirsRead() because IIsWebVirtualDir table not present"); ExitFunction1(hr = S_FALSE); } // loop through all the vdirs while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) { // Get the Component first. If there is a Component and it is not being modified during // this transaction, skip processing this whole record. hr = WcaGetRecordString(hRec, vdqComponent, &pwzData); ExitOnFailure(hr, "failed to get IIsWebVirtualDir.Component"); hr = WcaGetRecordInteger(hRec, vdqInstalled, (int *)&isInstalled); ExitOnFailure(hr, "Failed to get Component installed state for virtual dir"); hr = WcaGetRecordInteger(hRec, vdqAction, (int *)&isAction); ExitOnFailure(hr, "Failed to get Component action state for virtual dir"); if (!WcaIsInstalling(isInstalled, isAction) && !WcaIsReInstalling(isInstalled, isAction) && !WcaIsUninstalling(isInstalled, isAction)) { continue; // skip this record. } hr = AddVirtualDirToList(ppsvdList); ExitOnFailure(hr, "failed to add virtual dir to list"); pvdir = *ppsvdList; hr = ::StringCchCopyW(pvdir->wzComponent, countof(pvdir->wzComponent), pwzData); ExitOnFailure1(hr, "failed to copy component name: %ls", pwzData); pvdir->isInstalled = isInstalled; pvdir->isAction = isAction; // get the web key hr = WcaGetRecordString(hRec, vdqWeb, &pwzData); ExitOnFailure(hr, "Failed to get Web for VirtualDir"); hr = ScaWebsGetBase(piMetabase, pswList, pwzData, pvdir->wzWebBase, countof(pvdir->wzWebBase), hWebBaseQuery); if (WcaIsUninstalling(isInstalled, isAction)) { // If we're uninstalling, ignore any failure to find the existing web hr = S_OK; } ExitOnFailure1(hr, "Failed to get base of web: %ls for VirtualDir", pwzData); hr = WcaGetRecordString(hRec, vdqAlias, &pwzData); ExitOnFailure(hr, "Failed to get Alias for VirtualDir"); if (0 != lstrlenW(pvdir->wzWebBase)) { hr = ::StringCchPrintfW(pvdir->wzVDirRoot, countof(pvdir->wzVDirRoot), L"%s/Root/%s", pvdir->wzWebBase, pwzData); ExitOnFailure(hr, "Failed to set VDirRoot for VirtualDir"); } // get the vdir's directory hr = WcaGetRecordString(hRec, vdqDirectory, &pwzData); ExitOnFailure(hr, "Failed to get Directory for VirtualDir"); // get the web's directory if (INSTALLSTATE_SOURCE == pvdir->isAction) { hr = WcaGetRecordString(hRec, vdqSourcePath, &pwzData); } else { hr = WcaGetRecordString(hRec, vdqTargetPath, &pwzData); } ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory"); // remove trailing backslash(es) while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\') { pwzData[lstrlenW(pwzData)-1] = 0; } hr = ::StringCchCopyW(pvdir->wzDirectory, countof(pvdir->wzDirectory), pwzData); ExitOnFailure(hr, "Failed to copy directory string to vdir object"); // get the security information for this web hr = WcaGetRecordString(hRec, vdqProperties, &pwzData); ExitOnFailure(hr, "Failed to get web directory identifier for VirtualDir"); if (*pwzData) { hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pvdir->swp); ExitOnFailure(hr, "Failed to get web directory for VirtualDir"); pvdir->fHasProperties = TRUE; } // get the application information for this web hr = WcaGetRecordString(hRec, vdqApplication, &pwzData); ExitOnFailure(hr, "Failed to get application identifier for VirtualDir"); if (*pwzData) { hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pvdir->swapp); ExitOnFailure(hr, "Failed to get application for VirtualDir"); pvdir->fHasApplication = TRUE; } hr = WcaGetRecordString(hRec, vdqVDir, &pwzData); ExitOnFailure(hr, "Failed to get VDir for VirtualDir"); if (*pwzData && *ppsmmList) { hr = ScaGetMimeMap(mmptVDir, pwzData, ppsmmList, &pvdir->psmm); ExitOnFailure(hr, "Failed to get mimemap for VirtualDir"); } if (*pwzData && *ppshhList) { hr = ScaGetHttpHeader(hhptVDir, pwzData, ppshhList, &pvdir->pshh); ExitOnFailure1(hr, "Failed to get custom HTTP headers for VirtualDir: %ls", pwzData); } if (*pwzData && *ppsweList) { hr = ScaGetWebError(weptVDir, pwzData, ppsweList, &pvdir->pswe); ExitOnFailure1(hr, "Failed to get custom web errors for VirtualDir: %ls", pwzData); } } if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "Failure while processing VirtualDirs"); LExit: WcaFinishUnwrapQuery(hWrapQuery); ReleaseStr(pwzData); return hr; }
/* **************************************************************** ScaUserExecute - Schedules user account creation or removal based on component state. ******************************************************************/ HRESULT ScaUserExecute( __in SCA_USER *psuList ) { HRESULT hr = S_OK; DWORD er = 0; PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; USER_INFO_0 *pUserInfo = NULL; LPWSTR pwzActionData = NULL; LPWSTR pwzRollbackData = NULL; for (SCA_USER *psu = psuList; psu; psu = psu->psuNext) { USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE; // Always put the User Name and Domain plus Attributes on the front of the CustomAction // data. Sometimes we'll add more data. Assert(psu->wzName); hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData); ExitOnFailure1(hr, "Failed to add user name to custom action data: %ls", psu->wzName); hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData); ExitOnFailure1(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain); hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); ExitOnFailure1(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); // Check to see if the user already exists since we have to be very careful when adding // and removing users. Note: MSDN says that it is safe to call these APIs from any // user, so we should be safe calling it during immediate mode. er = ::NetApiBufferAllocate(sizeof(USER_INFO_0), reinterpret_cast<LPVOID*>(&pUserInfo)); hr = HRESULT_FROM_WIN32(er); ExitOnFailure1(hr, "Failed to allocate memory to check existence of user: %ls", psu->wzName); LPCWSTR wzDomain = psu->wzDomain; if (wzDomain && *wzDomain) { er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, NULL, &pDomainControllerInfo); if (HRESULT_FROM_WIN32(er) == RPC_S_SERVER_UNAVAILABLE) { // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag er = ::DsGetDcNameW(NULL, wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo); } if (ERROR_SUCCESS == er) { wzDomain = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix } } er = ::NetUserGetInfo(wzDomain, psu->wzName, 0, reinterpret_cast<LPBYTE*>(pUserInfo)); if (NERR_Success == er) { ueUserExists = USER_EXISTS_YES; } else if (NERR_UserNotFound == er) { ueUserExists = USER_EXISTS_NO; } else { ueUserExists = USER_EXISTS_INDETERMINATE; hr = HRESULT_FROM_WIN32(er); WcaLog(LOGMSG_VERBOSE, "Failed to check existence of domain: %ls, user: %ls (error code 0x%x) - continuing", wzDomain, psu->wzName, hr); } if (WcaIsInstalling(psu->isInstalled, psu->isAction)) { // If the user exists, check to see if we are supposed to fail if user the exists before // the install. if (USER_EXISTS_YES == ueUserExists) { // Reinstalls will always fail if we don't remove the check for "fail if exists". if (WcaIsReInstalling(psu->isInstalled, psu->isAction)) { psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS; } if ((SCAU_FAIL_IF_EXISTS & (psu->iAttributes)) && !(SCAU_UPDATE_IF_EXISTS & (psu->iAttributes))) { hr = HRESULT_FROM_WIN32(NERR_UserExists); MessageExitOnFailure1(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName); } } // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER)) { INT iRollbackUserAttributes = psu->iAttributes; // If the user already exists, ensure this is accounted for in rollback if (USER_EXISTS_YES == ueUserExists) { iRollbackUserAttributes |= SCAU_DONT_CREATE_USER; } else { iRollbackUserAttributes &= ~SCAU_DONT_CREATE_USER; } hr = WcaWriteStringToCaData(psu->wzName, &pwzRollbackData); ExitOnFailure1(hr, "Failed to add user name to rollback custom action data: %ls", psu->wzName); hr = WcaWriteStringToCaData(psu->wzDomain, &pwzRollbackData); ExitOnFailure1(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain); hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); ExitOnFailure1(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey); // If the user already exists, add relevant group information to rollback data if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists) { hr = WriteGroupRollbackInfo(psu->wzName, psu->wzDomain, psu->psgGroups, &pwzRollbackData); ExitOnFailure(hr, "failed to add group information to rollback custom action data"); } hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"CreateUserRollback"), pwzRollbackData, COST_USER_DELETE); ExitOnFailure(hr, "failed to schedule CreateUserRollback"); } // // Schedule the creation now. // hr = WcaWriteStringToCaData(psu->wzPassword, &pwzActionData); ExitOnFailure1(hr, "failed to add user password to custom action data for user: %ls", psu->wzKey); // Add user's group information to custom action data hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); ExitOnFailure(hr, "failed to add group information to custom action data"); hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"CreateUser"), pwzActionData, COST_USER_ADD); ExitOnFailure(hr, "failed to schedule CreateUser"); } else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL)) { // Add user's group information - this will ensure the user can be removed from any groups they were added to, if the user isn't be deleted hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); ExitOnFailure(hr, "failed to add group information to custom action data"); // // Schedule the removal because the user exists and we don't have any flags set // that say, don't remove the user on uninstall. // // Note: We can't rollback the removal of a user which is why RemoveUser is a commit // CustomAction. hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE); ExitOnFailure(hr, "failed to schedule RemoveUser"); } ReleaseNullStr(pwzActionData); ReleaseNullStr(pwzRollbackData); if (pUserInfo) { ::NetApiBufferFree(static_cast<LPVOID>(pUserInfo)); pUserInfo = NULL; } if (pDomainControllerInfo) { ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo)); pDomainControllerInfo = NULL; } } LExit: ReleaseStr(pwzActionData); ReleaseStr(pwzRollbackData); if (pUserInfo) { ::NetApiBufferFree(static_cast<LPVOID>(pUserInfo)); } if (pDomainControllerInfo) { ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo)); } return hr; }
HRESULT MqiMessageQueueRead( MQI_MESSAGE_QUEUE_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; MQI_MESSAGE_QUEUE* pItm = NULL; LPWSTR pwzData = NULL; // loop through all partitions hr = WcaOpenExecuteView(vcsMessageQueueQuery, &hView); ExitOnFailure(hr, "Failed to execute view on MessageQueue table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // create entry pItm = (MQI_MESSAGE_QUEUE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MQI_MESSAGE_QUEUE)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); // get key hr = WcaGetRecordString(hRec, mqqMessageQueue, &pwzData); ExitOnFailure(hr, "Failed to get key"); StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); // get component install state hr = WcaGetRecordString(hRec, mqqComponent, &pwzData); ExitOnFailure(hr, "Failed to get component"); // get component install state er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); // get base priority hr = WcaGetRecordInteger(hRec, mqqBasePriority, &pItm->iBasePriority); ExitOnFailure(hr, "Failed to get base priority"); // get journal quota hr = WcaGetRecordInteger(hRec, mqqJournalQuota, &pItm->iJournalQuota); ExitOnFailure(hr, "Failed to get journal quota"); // get label hr = WcaGetRecordFormattedString(hRec, mqqLabel, &pwzData); ExitOnFailure(hr, "Failed to get label"); StringCchCopyW(pItm->wzLabel, countof(pItm->wzLabel), pwzData); // get multicast address hr = WcaGetRecordFormattedString(hRec, mqqMulticastAddress, &pwzData); ExitOnFailure(hr, "Failed to get multicast address"); StringCchCopyW(pItm->wzMulticastAddress, countof(pItm->wzMulticastAddress), pwzData); // get path name hr = WcaGetRecordFormattedString(hRec, mqqPathName, &pwzData); ExitOnFailure(hr, "Failed to get path name"); StringCchCopyW(pItm->wzPathName, countof(pItm->wzPathName), pwzData); // get privacy level hr = WcaGetRecordInteger(hRec, mqqPrivLevel, &pItm->iPrivLevel); ExitOnFailure(hr, "Failed to get privacy level"); // get quota hr = WcaGetRecordInteger(hRec, mqqQuota, &pItm->iQuota); ExitOnFailure(hr, "Failed to get quota"); // get service type guid hr = WcaGetRecordFormattedString(hRec, mqqServiceTypeGuid, &pwzData); ExitOnFailure(hr, "Failed to get service type guid"); StringCchCopyW(pItm->wzServiceTypeGuid, countof(pItm->wzServiceTypeGuid), pwzData); // get attributes hr = WcaGetRecordInteger(hRec, mqqAttributes, &pItm->iAttributes); ExitOnFailure(hr, "Failed to get attributes"); // increment counters if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) pList->iInstallCount++; if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) pList->iUninstallCount++; // add entry pItm->pNext = pList->pFirst; pList->pFirst = pItm; pItm = NULL; } if (E_NOMOREITEMS == hr) hr = S_OK; LExit: // clean up if (pItm) ::HeapFree(::GetProcessHeap(), 0, pItm); ReleaseStr(pwzData); return hr; }
HRESULT ScaVirtualDirsInstall( __in IMSAdminBase* piMetabase, __in SCA_VDIR* psvdList, __in SCA_APPPOOL * psapList ) { Assert(piMetabase); HRESULT hr = S_OK; SCA_VDIR* psvd = psvdList; int i; while (psvd) { // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created if (WcaIsReInstalling(psvd->isInstalled, psvd->isAction)) { if (psvd->fHasApplication) { hr = ScaDeleteApp(piMetabase, psvd->wzVDirRoot); ExitOnFailure(hr, "Failed to remove application for WebVDir as part of a reinstall"); } } if (WcaIsInstalling(psvd->isInstalled, psvd->isAction)) { hr = ScaCreateMetabaseKey(piMetabase, psvd->wzVDirRoot, L""); ExitOnFailure(hr, "Failed to create key for VirtualDir"); hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebVirtualDir"); ExitOnFailure(hr, "Failed to write key type for for VirtualDir"); i = 0x4000003e; // 1073741886; // default directory browsing rights hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)i)); ExitOnFailure(hr, "Failed to set directory browsing for VirtualDir"); hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)psvd->wzDirectory); ExitOnFailure(hr, "Failed to write Directory for VirtualDir"); if (psvd->fHasProperties) { ScaWriteWebDirProperties(piMetabase, psvd->wzVDirRoot, &psvd->swp); ExitOnFailure(hr, "Failed to write directory properties for VirtualDir"); } if (psvd->fHasApplication) { hr = ScaWriteWebApplication(piMetabase, psvd->wzVDirRoot, &psvd->swapp, psapList); ExitOnFailure(hr, "Failed to write application for VirtualDir"); } if (psvd->psmm) { hr = ScaWriteMimeMap(piMetabase, psvd->wzVDirRoot, psvd->psmm); ExitOnFailure(hr, "Failed to write mimemap for VirtualDir"); } if (psvd->pshh) { hr = ScaWriteHttpHeader(piMetabase, psvd->wzVDirRoot, psvd->pshh); ExitOnFailure(hr, "Failed to write custom HTTP headers for VirtualDir"); } if (psvd->pswe) { hr = ScaWriteWebError(piMetabase, weptVDir, psvd->wzVDirRoot, psvd->pswe); ExitOnFailure(hr, "Failed to write custom web errors for VirtualDir"); } } psvd = psvd->psvdNext; } LExit: return hr; }
HRESULT CpiApplicationRolesVerifyInstall( CPI_APPLICATION_ROLE_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogObject* piRoleObj = NULL; for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // referenced locaters or roles that are being installed if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))) continue; // if the role is referensed and is not a locater, it must be installed if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) MessageExitOnFailure1(hr = E_FAIL, msierrComPlusApplicationRoleDependency, "An application role is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); // role is a locater if (!pItm->fHasComponent) { // get collection object for role hr = FindObjectForApplicationRole(pItm, &piRoleObj); ExitOnFailure(hr, "Failed to find collection object for role"); // if the role was not found if (S_FALSE == hr) MessageExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationRoleNotFound, "An application role required by this installation was not found, key: %S", pItm->wzKey); } // role is supposed to be created else if (!CpiIsInstalled(pItm->isInstalled)) { do { // find roles with conflicting name or id hr = FindObjectForApplicationRole(pItm, NULL); ExitOnFailure(hr, "Failed to find collection object for role"); if (S_OK == hr) { er = WcaErrorMessage(msierrComPlusApplicationRoleConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitOnFailure1(hr = E_FAIL, "An application with a conflictiong name exists, key: %S", pItm->wzKey); break; case IDRETRY: break; case IDIGNORE: default: hr = S_FALSE; // indicate that this is not a conflict } } } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts } // clean up ReleaseNullObject(piRoleObj); } hr = S_OK; LExit: // clean up ReleaseObject(piRoleObj); return hr; }
static HRESULT MessageQueueTrusteePermissionsRead( LPCWSTR pwzQuery, MQI_MESSAGE_QUEUE_LIST* pMessageQueueList, MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; LPWSTR pwzData = NULL; MQI_MESSAGE_QUEUE_PERMISSION* pItm = NULL; // loop through all application roles hr = WcaOpenExecuteView(pwzQuery, &hView); ExitOnFailure(hr, "Failed to execute view on table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // create entry pItm = (MQI_MESSAGE_QUEUE_PERMISSION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MQI_MESSAGE_QUEUE_PERMISSION)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); // get key hr = WcaGetRecordString(hRec, mqpqMessageQueuePermission, &pwzData); ExitOnFailure(hr, "Failed to get key"); StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); // get component hr = WcaGetRecordString(hRec, mqpqComponent, &pwzData); ExitOnFailure(hr, "Failed to get component"); // get component install state er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); // get message queue hr = WcaGetRecordString(hRec, mqpqMessageQueue, &pwzData); ExitOnFailure(hr, "Failed to get application role"); hr = MqiMessageQueueFindByKey(pMessageQueueList, pwzData, &pItm->pMessageQueue); if (S_FALSE == hr) hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); ExitOnFailure(hr, "Failed to find message queue, key: %S", pwzData); // get user domain hr = WcaGetRecordFormattedString(hRec, mqpqDomain, &pwzData); ExitOnFailure(hr, "Failed to get domain"); StringCchCopyW(pItm->wzDomain, countof(pItm->wzDomain), pwzData); // get user name hr = WcaGetRecordFormattedString(hRec, mqpqName, &pwzData); ExitOnFailure(hr, "Failed to get name"); StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); // get permissions hr = WcaGetRecordInteger(hRec, mqpqPermissions, &pItm->iPermissions); ExitOnFailure(hr, "Failed to get permissions"); // set references & increment counters if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) pList->iInstallCount++; if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) pList->iUninstallCount++; // add entry if (pList->pFirst) pItm->pNext = pList->pFirst; pList->pFirst = pItm; pItm = NULL; } if (E_NOMOREITEMS == hr) hr = S_OK; LExit: // clean up ReleaseStr(pwzData); if (pItm) ::HeapFree(::GetProcessHeap(), 0, pItm); return hr; }
HRESULT CpiApplicationRolesRead( CPI_APPLICATION_LIST* pAppList, CPI_APPLICATION_ROLE_LIST* pAppRoleList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; CPI_APPLICATION_ROLE* pItm = NULL; LPWSTR pwzData = NULL; BOOL fMatchingArchitecture = FALSE; // loop through all application roles hr = WcaOpenExecuteView(vcsApplicationRoleQuery, &hView); ExitOnFailure(hr, "Failed to execute view on ComPlusApplicationRole table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // get component hr = WcaGetRecordString(hRec, arqComponent, &pwzData); ExitOnFailure(hr, "Failed to get component"); // check if the component is our processor architecture if (pwzData && *pwzData) { hr = CpiVerifyComponentArchitecure(pwzData, &fMatchingArchitecture); ExitOnFailure(hr, "Failed to get component architecture."); if (!fMatchingArchitecture) { continue; // not the same architecture, ignore } } // create entry pItm = (CPI_APPLICATION_ROLE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CPI_APPLICATION_ROLE)); if (!pItm) ExitFunction1(hr = E_OUTOFMEMORY); // get component install state if (pwzData && *pwzData) { pItm->fHasComponent = TRUE; er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction); ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state"); } // get key hr = WcaGetRecordString(hRec, arqApplicationRole, &pwzData); ExitOnFailure(hr, "Failed to get key"); StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData); // get application hr = WcaGetRecordString(hRec, arqApplication, &pwzData); ExitOnFailure(hr, "Failed to get application"); hr = CpiApplicationFindByKey(pAppList, pwzData, &pItm->pApplication); if (S_FALSE == hr) hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); ExitOnFailure1(hr, "Failed to find application, key: %S", pwzData); // get name hr = WcaGetRecordFormattedString(hRec, arqName, &pwzData); ExitOnFailure(hr, "Failed to get name"); StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData); // get properties if (CpiTableExists(cptComPlusApplicationRoleProperty)) { hr = CpiPropertiesRead(vcsApplicationRolePropertyQuery, pItm->wzKey, pdlApplicationRoleProperties, &pItm->pProperties, &pItm->iPropertyCount); ExitOnFailure(hr, "Failed to get properties"); } // set references & increment counters if (pItm->fHasComponent) { if (WcaIsInstalling(pItm->isInstalled, pItm->isAction)) { CpiApplicationAddReferenceInstall(pItm->pApplication); pAppRoleList->iInstallCount++; } if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) { CpiApplicationAddReferenceUninstall(pItm->pApplication); pAppRoleList->iUninstallCount++; } } // add entry if (pAppRoleList->pFirst) pItm->pNext = pAppRoleList->pFirst; pAppRoleList->pFirst = pItm; pItm = NULL; } if (E_NOMOREITEMS == hr) hr = S_OK; LExit: // clean up if (pItm) FreeApplicationRole(pItm); ReleaseStr(pwzData); return hr; }
HRESULT ScaUserRead( __out SCA_USER** ppsuList ) { //Assert(FALSE); Assert(ppsuList); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec, hUserRec, hUserGroupView; LPWSTR pwzData = NULL; BOOL fUserGroupExists = FALSE; SCA_USER *psu = NULL; INSTALLSTATE isInstalled, isAction; if (S_OK != WcaTableExists(L"User")) { WcaLog(LOGMSG_VERBOSE, "User Table does not exist, exiting"); ExitFunction1(hr = S_FALSE); } if (S_OK == WcaTableExists(L"UserGroup")) { fUserGroupExists = TRUE; } // // loop through all the users // hr = WcaOpenExecuteView(vActionableQuery, &hView); ExitOnFailure(hr, "failed to open view on User table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hr = WcaGetRecordString(hRec, vaqComponent, &pwzData); ExitOnFailure(hr, "failed to get User.Component"); er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &isInstalled, &isAction); hr = HRESULT_FROM_WIN32(er); ExitOnFailure(hr, "failed to get Component state for User"); // don't bother if we aren't installing or uninstalling this component if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction)) { // // Add the user to the list and populate it's values // hr = AddUserToList(ppsuList); ExitOnFailure(hr, "failed to add user to list"); psu = *ppsuList; psu->isInstalled = isInstalled; psu->isAction = isAction; hr = ::StringCchCopyW(psu->wzComponent, countof(psu->wzComponent), pwzData); ExitOnFailure1(hr, "failed to copy component name: %ls", pwzData); hr = WcaGetRecordString(hRec, vaqUser, &pwzData); ExitOnFailure(hr, "failed to get User.User"); hr = ::StringCchCopyW(psu->wzKey, countof(psu->wzKey), pwzData); ExitOnFailure1(hr, "failed to copy user key: %ls", pwzData); hr = WcaGetRecordFormattedString(hRec, vaqName, &pwzData); ExitOnFailure(hr, "failed to get User.Name"); hr = ::StringCchCopyW(psu->wzName, countof(psu->wzName), pwzData); ExitOnFailure1(hr, "failed to copy user name: %ls", pwzData); hr = WcaGetRecordFormattedString(hRec, vaqDomain, &pwzData); ExitOnFailure(hr, "failed to get User.Domain"); hr = ::StringCchCopyW(psu->wzDomain, countof(psu->wzDomain), pwzData); ExitOnFailure1(hr, "failed to copy user domain: %ls", pwzData); hr = WcaGetRecordFormattedString(hRec, vaqPassword, &pwzData); ExitOnFailure(hr, "failed to get User.Password"); hr = ::StringCchCopyW(psu->wzPassword, countof(psu->wzPassword), pwzData); ExitOnFailure(hr, "failed to copy user password"); hr = WcaGetRecordInteger(hRec, vaqAttributes, &psu->iAttributes); ExitOnFailure(hr, "failed to get User.Attributes"); // Check if this user is to be added to any groups if (fUserGroupExists) { hUserRec = ::MsiCreateRecord(1); hr = WcaSetRecordString(hUserRec, 1, psu->wzKey); ExitOnFailure(hr, "Failed to create user record for querying UserGroup table"); hr = WcaOpenView(vcsUserGroupQuery, &hUserGroupView); ExitOnFailure1(hr, "Failed to open view on UserGroup table for user %ls", psu->wzKey); hr = WcaExecuteView(hUserGroupView, hUserRec); ExitOnFailure1(hr, "Failed to execute view on UserGroup table for user: %ls", psu->wzKey); while (S_OK == (hr = WcaFetchRecord(hUserGroupView, &hRec))) { hr = WcaGetRecordString(hRec, vugqGroup, &pwzData); ExitOnFailure(hr, "failed to get UserGroup.Group"); hr = AddGroupToList(&(psu->psgGroups)); ExitOnFailure(hr, "failed to add group to list"); hr = ScaGetGroup(pwzData, psu->psgGroups); ExitOnFailure1(hr, "failed to get information for group: %ls", pwzData); } if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "failed to enumerate selected rows from UserGroup table"); } } } if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "failed to enumerate selected rows from User table"); LExit: ReleaseStr(pwzData); return hr; }
/****************************************************************** CaSchedSecureObjects - entry point for CaReadSecureObjects Custom Action called as Type 1 CustomAction (binary DLL) from Windows Installer in InstallExecuteSequence before CaSecureObjects ******************************************************************/ extern "C" UINT __stdcall SchedSecureObjects( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedSecureObjects"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzData = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzTargetPath = NULL; LPWSTR pwzFormattedString = NULL; int iRoot = 0; int iAllUsers = 0; LPWSTR pwzKey = NULL; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; MSIHANDLE hViewObject = NULL; // Don't free this since it's always a copy of either hViewService or hViewCreateFolder PMSIHANDLE hViewService = NULL; PMSIHANDLE hViewCreateFolder = NULL; PMSIHANDLE hViewFile = NULL; PMSIHANDLE hViewRegistry = NULL; PMSIHANDLE hRecObject = NULL; INSTALLSTATE isInstalled; INSTALLSTATE isAction; LPWSTR pwzCustomActionData = NULL; DWORD cchCustomActionData = 0; DWORD cObjects = 0; eOBJECTTYPE eType = OT_UNKNOWN; // // initialize // hr = WcaInitialize(hInstall, "SchedSecureObjects"); ExitOnFailure(hr, "failed to initialize"); // // loop through all the objects to be secured // hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView); ExitOnFailure(hr, "failed to open view on SecureObjects table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hViewObject = NULL; eType = OT_UNKNOWN; hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); ExitOnFailure(hr, "failed to get object table"); // ensure we're looking at a known table if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) { eType = OT_SERVICE; } else if (0 == lstrcmpW(L"CreateFolder", pwzTable)) { eType = OT_FOLDER; } else if (0 == lstrcmpW(L"File", pwzTable)) { eType = OT_FILE; } else if (0 == lstrcmpW(L"Registry", pwzTable)) { eType = OT_REGISTRY; } else { ExitOnFailure1(hr = E_INVALIDARG, "unknown SecureObject.Table: %S", pwzTable); } // if we haven't opened a view on the ServiceInstall/CreateFolder table, do that now if (OT_SERVICE == eType) { if (!hViewService) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_SERVICECOMPONENT, &hViewService); ExitOnFailure(hr, "failed to open view on ServiceInstall table"); } hViewObject = hViewService; } else if (OT_FOLDER == eType) { if (!hViewCreateFolder) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_CREATEFOLDERCOMPONENT, &hViewCreateFolder); ExitOnFailure(hr, "failed to open view on CreateFolder table"); } hViewObject = hViewCreateFolder; } else if (OT_FILE== eType) { if (!hViewFile) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_FILECOMPONENT, &hViewFile); ExitOnFailure(hr, "failed to open view on CreateFolder table"); } hViewObject = hViewFile; } else if (OT_REGISTRY== eType) { if (!hViewRegistry) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_REGISTRYCOMPONENT, &hViewRegistry); ExitOnFailure(hr, "failed to open view on CreateFolder table"); } hViewObject = hViewRegistry; } Assert(hViewObject); // execute a view looking for the object's Component_ hr = WcaExecuteView(hViewObject, hRec); ExitOnFailure1(hr, "failed to execute view on %S table", pwzData); hr = WcaFetchSingleRecord(hViewObject, &hRecObject); ExitOnFailure(hr, "failed to fetch Component for secure object"); hr = WcaGetRecordString(hRecObject, QSOC_COMPONENT, &pwzData); ExitOnFailure(hr, "failed to get Component name for secure object"); // // if we are installing this Component // er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %S", pwzData); if (WcaIsInstalling(isInstalled, isAction)) { // add the data to the CustomActionData hr = WcaGetRecordString(hRecObject, QSOC_OBJECTNAME, &pwzData); ExitOnFailure(hr, "failed to get name of object"); if (OT_SERVICE == eType) { hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else if (OT_FOLDER == eType) { hr = WcaGetTargetPath(pwzData, &pwzTargetPath); ExitOnFailure1(hr, "failed to get target path for directory id: %S", pwzData); hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else if (OT_FILE == eType) { hr = StrAllocFormatted(&pwzFormattedString, L"[#%s]", pwzData); ExitOnFailure1(hr, "failed to create formatted string for securing file object: %S", pwzData); hr = WcaGetFormattedString(pwzFormattedString, &pwzTargetPath); ExitOnFailure2(hr, "failed to get file path from formatted string: %S for secure object: %S", pwzFormattedString, pwzData); hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else if (OT_REGISTRY == eType) { hr = WcaGetRecordInteger(hRecObject, QSOC_REGROOT, &iRoot); ExitOnFailure1(hr, "Failed to get reg key root for secure object: %S", pwzData); hr = WcaGetRecordFormattedString(hRecObject, QSOC_REGKEY, &pwzKey); ExitOnFailure1(hr, "Failed to get reg key for secure object: %S", pwzData); // Decode the root value if (-1 == iRoot) { // They didn't specify a root so that means it's either HKCU or HKLM depending on ALLUSERS property hr = WcaGetIntProperty(L"ALLUSERS", &iAllUsers); ExitOnFailure(hr, "failed to get value of ALLUSERS property"); if (1 == iAllUsers) { hr = StrAllocString(&pwzTargetPath, L"MACHINE\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); } else { hr = StrAllocString(&pwzTargetPath, L"CURRENT_USER\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); } } else if (/*msidbRegistryRootClassesRoot*/ 0 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"CLASSES_ROOT\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCR root"); } else if (/*msidbRegistryRootCurrentUser*/ 1 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"CURRENT_USER\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); } else if (/*msidbRegistryRootLocalMachine*/ 2 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"MACHINE\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); } else if (/*msidbRegistryRootUsers*/ 3 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"USERS\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKU root"); } else { ExitOnFailure2(hr = E_UNEXPECTED, "Unknown registry key root specified for secure object: '%S' root: %d", pwzData, iRoot); } hr = StrAllocConcat(&pwzTargetPath, pwzKey, 0); ExitOnFailure2(hr, "Failed to concat key: %S for secure object: %S", pwzKey, pwzData); hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else { AssertSz(FALSE, "How did you get here?"); } hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordFormattedString(hRec, QSO_DOMAIN, &pwzData); ExitOnFailure(hr, "failed to get domain for user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordFormattedString(hRec, QSO_USER, &pwzData); ExitOnFailure(hr, "failed to get user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData); ExitOnFailure(hr, "failed to get domain for user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); cObjects++; } } // 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"); // // schedule the custom action and add to progress bar // if (pwzCustomActionData && *pwzCustomActionData) { Assert(0 < cObjects); hr = WcaDoDeferredAction(L"ExecSecureObjects", pwzCustomActionData, cObjects * COST_SECUREOBJECT); ExitOnFailure(hr, "failed to schedule ExecSecureObjects action"); } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzTable); ReleaseStr(pwzTargetPath); ReleaseStr(pwzFormattedString); ReleaseStr(pwzKey); if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
HRESULT ScaVirtualDirsInstall7( __in SCA_VDIR7* psvdList, __in SCA_APPPOOL * psapList ) { HRESULT hr = S_OK; SCA_VDIR7* psvd = psvdList; LPWSTR wzPath = NULL; WCHAR wzAppPoolName[MAX_PATH]; while (psvd) { if (WcaIsInstalling(psvd->isInstalled, psvd->isAction)) { // First write all applications, this is necessary since vdirs must be nested under the applications. if (psvd->fHasApplication) { //create the application for this vdir application hr = ScaWriteConfigID(IIS_APPLICATION); ExitOnFailure(hr, "Failed to write app ID"); hr = ScaWriteConfigID(IIS_CREATE); ExitOnFailure(hr, "Failed to write app action"); #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaWriteConfigString(psvd->wzWebName); //site name key ExitOnFailure(hr, "Failed to write app web key"); hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot); ExitOnFailure(hr, "Failed to create app path"); hr = ScaWriteConfigString(wzPath); // App Path ExitOnFailure(hr, "Failed to write app path root "); if (!*psvd->swapp.wzAppPool) { //This Application goes in default appPool hr = ScaWriteConfigString(L""); // App Pool } else { //get apppool from WebApplication #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaFindAppPool7(psvd->swapp.wzAppPool, wzAppPoolName, countof(wzAppPoolName), psapList); ExitOnFailure(hr, "Failed to read app pool from application"); hr = ScaWriteConfigString(wzAppPoolName); // App Pool ExitOnFailure(hr, "Failed to write appPool for vdir"); } } } psvd = psvd->psvdNext; } // Reset our linked list and write all the VDirs psvd = psvdList; while (psvd) { if (WcaIsInstalling(psvd->isInstalled, psvd->isAction)) { //create the Vdir hr = ScaWriteConfigID(IIS_VDIR); ExitOnFailure(hr, "Failed write VirDir ID") hr = ScaWriteConfigID(IIS_CREATE); ExitOnFailure(hr, "Failed write VirDir action") #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaWriteConfigString(psvd->wzWebName); //site name key ExitOnFailure(hr, "Failed write VirDir web name"); hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot); ExitOnFailure(hr, "Failed to create vdir path"); hr = ScaWriteConfigString(wzPath); //vdir path ExitOnFailure(hr, "Failed write VirDir path") #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaWriteConfigString(psvd->wzDirectory); //physical dir ExitOnFailure(hr, "Failed write VirDir dir"); if (psvd->fHasProperties) { ScaWriteWebDirProperties7(psvd->wzWebName, psvd->wzVDirRoot, &psvd->swp); ExitOnFailure(hr, "Failed to write directory properties for VirtualDir"); } if (psvd->fHasApplication) { hr = ScaWriteWebApplication7(psvd->wzWebName, psvd->wzVDirRoot, &psvd->swapp, psapList); ExitOnFailure(hr, "Failed to write application for VirtualDir"); } if (psvd->psmm) { hr = ScaWriteMimeMap7(psvd->wzWebName, psvd->wzVDirRoot, psvd->psmm); ExitOnFailure(hr, "Failed to write mimemap for VirtualDir"); } if (psvd->pshh) { hr = ScaWriteHttpHeader7(psvd->wzWebName, psvd->wzVDirRoot, psvd->pshh); ExitOnFailure(hr, "Failed to write custom HTTP headers for VirtualDir"); } if (psvd->pswe) { hr = ScaWriteWebError7(psvd->wzWebName, psvd->wzVDirRoot, psvd->pswe); ExitOnFailure(hr, "Failed to write custom web errors for VirtualDir"); } } psvd = psvd->psvdNext; } LExit: ReleaseStr(wzPath); return hr; }
/****************************************************************** 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); }