/******************************************************************** WixQueryOsDirs - entry point for WixQueryOsDirs custom action Called as Type 1 custom action (DLL from the Binary table) from Windows Installer to set properties that identify predefined directories ********************************************************************/ extern "C" UINT __stdcall WixQueryOsDirs( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; hr = WcaInitialize(hInstall, "WixQueryOsDirs"); ExitOnFailure(hr, "WixQueryOsDirs failed to initialize"); // get the paths of the CSIDLs that represent real paths and for which MSI // doesn't yet have standard folder properties WCHAR path[MAX_PATH]; if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_ADMINTOOLS", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_ALTSTARTUP", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_CDBURN_AREA, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_CDBURN_AREA", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_ADMINTOOLS", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_ALTSTARTUP", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_DOCUMENTS", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_FAVORITES", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_MUSIC, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_MUSIC", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_PICTURES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_PICTURES", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_VIDEO, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_VIDEO", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COOKIES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COOKIES", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_DESKTOP", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_HISTORY, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_HISTORY", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_INTERNET_CACHE, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_INTERNET_CACHE", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_MYMUSIC", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_MYPICTURES", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYVIDEO, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_MYVIDEO", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_NETHOOD", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_PERSONAL", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_PRINTHOOD", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_PROFILE", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_RECENT", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RESOURCES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_RESOURCES", path); } LExit: if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** ExecXmlConfig - entry point for XmlConfig Custom Action *******************************************************************/ extern "C" UINT __stdcall ExecXmlConfig( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ExecXmlConfig"); HRESULT hr = S_OK; HRESULT hrOpenFailure = S_OK; UINT er = ERROR_SUCCESS; BOOL fIsWow64Process = FALSE; BOOL fIsFSRedirectDisabled = FALSE; BOOL fPreserveDate = FALSE; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzData = NULL; LPWSTR pwzFile = NULL; LPWSTR pwzElementPath = NULL; LPWSTR pwzVerifyPath = NULL; LPWSTR pwzName = NULL; LPWSTR pwzValue = NULL; LPWSTR pwz = NULL; int cAdditionalChanges = 0; IXMLDOMDocument* pixd = NULL; IXMLDOMNode* pixn = NULL; IXMLDOMNode* pixnVerify = NULL; IXMLDOMNode* pixnNewNode = NULL; IXMLDOMNode* pixnRemovedChild = NULL; IXMLDOMDocument* pixdNew = NULL; IXMLDOMElement* pixeNew = NULL; FILETIME ft; int id = IDRETRY; eXmlAction xa; eXmlPreserveDate xd; // initialize hr = WcaInitialize(hInstall, "ExecXmlConfig"); ExitOnFailure(hr, "failed to initialize"); hr = XmlInitialize(); ExitOnFailure(hr, "failed to initialize xml utilities"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); ExitOnFailure(hr, "failed to process CustomActionData"); // Initialize the Wow64 API - store the result in fWow64APIPresent // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases WcaInitializeWow64(); fIsWow64Process = WcaIsWow64Process(); if (xaOpenFile != xa && xaOpenFilex64 != xa) { ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data"); } // loop through all the passed in data while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzFile); ExitOnFailure(hr, "failed to read file name from custom action data"); // Default to not preserve date, preserve it if any modifications require us to fPreserveDate = FALSE; // Open the file ReleaseNullObject(pixd); if (xaOpenFilex64 == xa) { if (!fIsWow64Process) { hr = E_NOTIMPL; ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW."); } hr = WcaDisableWow64FSRedirection(); ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); fIsFSRedirectDisabled = TRUE; } hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd); if (FAILED(hr)) { // Ignore the return code for now. If they try to add something, we'll fail the install. If all they do is remove stuff then it doesn't matter. hrOpenFailure = hr; hr = S_OK; } else { hrOpenFailure = S_OK; } WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile); while (pwz && *pwz) { // If we skip past an element that has additional changes we need to strip them off the stream before // moving on to the next element. Do that now and then restart the outer loop. if (cAdditionalChanges > 0) { while (cAdditionalChanges > 0) { hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); cAdditionalChanges--; } continue; } hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); ExitOnFailure(hr, "failed to process CustomActionData"); // Break if we need to move on to a different file if (xaOpenFile == xa || xaOpenFilex64 == xa) { break; } hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd); ExitOnFailure(hr, "failed to process CustomActionData"); if (xdPreserve == xd) { fPreserveDate = TRUE; } // Get path, name, and value to be written hr = WcaReadStringFromCaData(&pwz, &pwzElementPath); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzVerifyPath); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, &cAdditionalChanges); ExitOnFailure(hr, "failed to process CustomActionData"); // If we failed to open the file and we're adding something to the file, we've got a problem. Otherwise, just continue on since the file's already gone. if (FAILED(hrOpenFailure)) { if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) { MessageExitOnFailure1(hr = hrOpenFailure, msierrXmlConfigFailedOpen, "failed to load XML file: %ls", pwzFile); } else { continue; } } // Select the node we're about to modify ReleaseNullObject(pixn); hr = XmlSelectSingleNode(pixd, pwzElementPath, &pixn); // If we failed to find the node that we are going to add to, we've got a problem. Otherwise, just continue since the node's already gone. if (S_FALSE == hr) { if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) { hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); } else { hr = S_OK; continue; } } MessageExitOnFailure2(hr, msierrXmlConfigFailedSelect, "failed to find node: %ls in XML file: %ls", pwzElementPath, pwzFile); // Make the modification switch (xa) { case xaWriteValue: if (pwzName && *pwzName) { // We're setting an attribute hr = XmlSetAttribute(pixn, pwzName, pwzValue); ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); } else { // We're setting the text of the node hr = XmlSetText(pixn, pwzValue); ExitOnFailure2(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzElementPath); } break; case xaWriteDocument: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { // We found the verify path which means we have no further work to do continue; } ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath); } hr = XmlLoadDocumentEx(pwzValue, XML_LOAD_PRESERVE_WHITESPACE, &pixdNew); ExitOnFailure(hr, "Failed to load value as document."); hr = pixdNew->get_documentElement(&pixeNew); ExitOnFailure(hr, "Failed to get document element."); hr = pixn->appendChild(pixeNew, NULL); ExitOnFailure(hr, "Failed to append document element on to parent element."); ReleaseNullObject(pixeNew); ReleaseNullObject(pixdNew); break; case xaCreateElement: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { // We found the verify path which means we have no further work to do continue; } ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath); } hr = XmlCreateChild(pixn, pwzName, &pixnNewNode); ExitOnFailure1(hr, "failed to create child element: %ls", pwzName); if (pwzValue && *pwzValue) { hr = XmlSetText(pixnNewNode, pwzValue); ExitOnFailure2(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName); } while (cAdditionalChanges > 0) { hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); // Set the additional attribute hr = XmlSetAttribute(pixnNewNode, pwzName, pwzValue); ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); cAdditionalChanges--; } ReleaseNullObject(pixnNewNode); break; case xaDeleteValue: if (pwzName && *pwzName) { // Delete the attribute hr = XmlRemoveAttribute(pixn, pwzName); ExitOnFailure1(hr, "failed to remove attribute: %ls", pwzName); } else { // Clear the text value for the node hr = XmlSetText(pixn, L""); ExitOnFailure(hr, "failed to clear text value"); } break; case xaDeleteElement: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { hr = pixn->removeChild(pixnVerify, &pixnRemovedChild); ExitOnFailure(hr, "failed to remove created child element"); ReleaseNullObject(pixnRemovedChild); } else { WcaLog(LOGMSG_VERBOSE, "Failed to select path %ls for deleting. Skipping...", pwzVerifyPath); hr = S_OK; } } else { // TODO: This requires a VerifyPath to delete an element. Should we support not having one? WcaLog(LOGMSG_VERBOSE, "No VerifyPath specified for delete element of ID: %ls", pwzElementPath); } break; default: ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data"); break; } } // Now that we've made all of the changes to this file, save it and move on to the next if (S_OK == hrOpenFailure) { if (fPreserveDate) { hr = FileGetTime(pwzFile, NULL, NULL, &ft); ExitOnFailure1(hr, "failed to get modified time of file : %ls", pwzFile); } int iSaveAttempt = 0; do { hr = XmlSaveDocument(pixd, pwzFile); if (FAILED(hr)) { id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile); switch (id) { case IDABORT: ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); case IDRETRY: hr = S_FALSE; // hit me, baby, one more time break; case IDIGNORE: hr = S_OK; // pretend everything is okay and bail break; case 0: // No UI case, MsiProcessMessage returns 0 if (STIERR_SHARING_VIOLATION == hr) { // Only in case of sharing violation do we retry 30 times, once a second. if (iSaveAttempt < 30) { hr = S_FALSE; ++iSaveAttempt; WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt); Sleep(1000); } else { ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); } } break; default: // Unknown error ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); } } } while (S_FALSE == hr); if (fPreserveDate) { hr = FileSetTime(pwzFile, NULL, NULL, &ft); ExitOnFailure1(hr, "failed to set modified time of file : %ls", pwzFile); } if (fIsFSRedirectDisabled) { fIsFSRedirectDisabled = FALSE; WcaRevertWow64FSRedirection(); } } } LExit: // Make sure we revert FS Redirection if necessary before exiting if (fIsFSRedirectDisabled) { fIsFSRedirectDisabled = FALSE; WcaRevertWow64FSRedirection(); } WcaFinalizeWow64(); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzFile); ReleaseStr(pwzElementPath); ReleaseStr(pwzVerifyPath); ReleaseStr(pwzName); ReleaseStr(pwzValue); ReleaseObject(pixeNew); ReleaseObject(pixdNew); ReleaseObject(pixn); ReleaseObject(pixd); ReleaseObject(pixnNewNode); ReleaseObject(pixnRemovedChild); XmlUninitialize(); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/****************************************************************** SchedFirewallExceptions - immediate custom action worker to register and remove firewall exceptions. ********************************************************************/ static UINT SchedFirewallExceptions( __in MSIHANDLE hInstall, WCA_TODO todoSched ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; int cFirewallExceptions = 0; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzName = NULL; LPWSTR pwzRemoteAddresses = NULL; LPWSTR pwzPort = NULL; int iProtocol = 0; int iAttributes = 0; int iProfile = 0; LPWSTR pwzProgram = NULL; LPWSTR pwzComponent = NULL; LPWSTR pwzFormattedFile = NULL; LPWSTR pwzDescription = NULL; // initialize hr = WcaInitialize(hInstall, "SchedFirewallExceptions"); ExitOnFailure(hr, "failed to initialize"); // anything to do? if (S_OK != WcaTableExists(L"WixFirewallException")) { WcaLog(LOGMSG_STANDARD, "WixFirewallException table doesn't exist, so there are no firewall exceptions to configure."); ExitFunction(); } // query and loop through all the firewall exceptions hr = WcaOpenExecuteView(vcsFirewallExceptionQuery, &hView); ExitOnFailure(hr, "failed to open view on WixFirewallException table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hr = WcaGetRecordFormattedString(hRec, feqName, &pwzName); ExitOnFailure(hr, "failed to get firewall exception name"); hr = WcaGetRecordFormattedString(hRec, feqRemoteAddresses, &pwzRemoteAddresses); ExitOnFailure(hr, "failed to get firewall exception remote addresses"); hr = WcaGetRecordFormattedString(hRec, feqPort, &pwzPort); ExitOnFailure(hr, "failed to get firewall exception port"); hr = WcaGetRecordInteger(hRec, feqProtocol, &iProtocol); ExitOnFailure(hr, "failed to get firewall exception protocol"); hr = WcaGetRecordFormattedString(hRec, feqProgram, &pwzProgram); ExitOnFailure(hr, "failed to get firewall exception program"); hr = WcaGetRecordInteger(hRec, feqAttributes, &iAttributes); ExitOnFailure(hr, "failed to get firewall exception attributes"); hr = WcaGetRecordInteger(hRec, feqProfile, &iProfile); ExitOnFailure(hr, "failed to get firewall exception profile"); hr = WcaGetRecordString(hRec, feqComponent, &pwzComponent); ExitOnFailure(hr, "failed to get firewall exception component"); hr = WcaGetRecordString(hRec, feqDescription, &pwzDescription); ExitOnFailure(hr, "failed to get firewall description"); // figure out what we're doing for this exception, treating reinstall the same as install WCA_TODO todoComponent = WcaGetComponentToDo(pwzComponent); if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched) { WcaLog(LOGMSG_STANDARD, "Component '%ls' action state (%d) doesn't match request (%d)", pwzComponent, todoComponent, todoSched); continue; } // action :: name :: profile :: remoteaddresses :: attributes :: target :: {port::protocol | path} ++cFirewallExceptions; hr = WcaWriteIntegerToCaData(todoComponent, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception action to custom action data"); hr = WcaWriteStringToCaData(pwzName, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception name to custom action data"); hr = WcaWriteIntegerToCaData(iProfile, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception profile to custom action data"); hr = WcaWriteStringToCaData(pwzRemoteAddresses, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception remote addresses to custom action data"); hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception attributes to custom action data"); if (*pwzProgram) { // If program is defined, we have an application exception. hr = WcaWriteIntegerToCaData(fetApplication, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception target (application) to custom action data"); hr = WcaWriteStringToCaData(pwzProgram, &pwzCustomActionData); ExitOnFailure(hr, "failed to write application path to custom action data"); } else { // we have a port-only exception hr = WcaWriteIntegerToCaData(fetPort, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception target (port) to custom action data"); } hr = WcaWriteStringToCaData(pwzPort, &pwzCustomActionData); ExitOnFailure(hr, "failed to write application path to custom action data"); hr = WcaWriteIntegerToCaData(iProtocol, &pwzCustomActionData); ExitOnFailure(hr, "failed to write exception protocol to custom action data"); hr = WcaWriteStringToCaData(pwzDescription, &pwzCustomActionData); ExitOnFailure(hr, "failed to write firewall rule description to custom action data"); } // reaching the end of the list is actually a good thing, not an error if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "failure occured while processing WixFirewallException table"); // schedule ExecFirewallExceptions if there's anything to do if (pwzCustomActionData && *pwzCustomActionData) { WcaLog(LOGMSG_STANDARD, "Scheduling firewall exception (%ls)", pwzCustomActionData); if (WCA_TODO_INSTALL == todoSched) { hr = WcaDoDeferredAction(L"WixRollbackFirewallExceptionsInstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall install exceptions rollback"); hr = WcaDoDeferredAction(L"WixExecFirewallExceptionsInstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall install exceptions execution"); } else { hr = WcaDoDeferredAction(L"WixRollbackFirewallExceptionsUninstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions rollback"); hr = WcaDoDeferredAction(L"WixExecFirewallExceptionsUninstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION); ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions execution"); } } else { WcaLog(LOGMSG_STANDARD, "No firewall exceptions scheduled"); } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzName); ReleaseStr(pwzRemoteAddresses); ReleaseStr(pwzPort); ReleaseStr(pwzProgram); ReleaseStr(pwzComponent); ReleaseStr(pwzDescription); ReleaseStr(pwzFormattedFile); return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er); }
/* Checks if database directory or service are modified by user For example, service may point to different mysqld.exe that it was originally installed, or some different service might use this database directory. This would normally mean user has done an upgrade of the database and in this case uninstall should neither delete service nor database directory. If this function find that service is modified by user (mysqld.exe used by service does not point to the installation bin directory), MSI public variable SERVICENAME is removed, if DATADIR is used by some other service, variables DATADIR and CLEANUPDATA are removed. The effect of variable removal is that service does not get uninstalled and datadir is not touched by uninstallation. Note that this function is running without elevation and does not use anything that would require special privileges. */ extern "C" UINT CheckDBInUse(MSIHANDLE hInstall) { static BYTE buf[256*1024]; /* largest possible buffer for EnumServices */ static char config_buffer[8*1024]; /*largest buffer for QueryServiceConfig */ HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; wchar_t *servicename= NULL; wchar_t *datadir= NULL; wchar_t *bindir=NULL; SC_HANDLE scm = NULL; ULONG bufsize = sizeof(buf); ULONG bufneed = 0x00; ULONG num_services = 0x00; LPENUM_SERVICE_STATUS_PROCESS info = NULL; hr = WcaInitialize(hInstall, __FUNCTION__); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); WcaGetProperty(L"SERVICENAME", &servicename); WcaGetProperty(L"DATADIR", &datadir); WcaGetFormattedString(L"[INSTALLDIR]bin\\", &bindir); WcaLog(LOGMSG_STANDARD,"SERVICENAME=%S, DATADIR=%S, bindir=%S", servicename, datadir, bindir); scm = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT); if (scm == NULL) { ExitOnFailure(E_FAIL, "OpenSCManager failed"); } BOOL ok= EnumServicesStatusExW( scm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, buf, bufsize, &bufneed, &num_services, NULL, NULL); if(!ok) { WcaLog(LOGMSG_STANDARD, "last error %d", GetLastError()); ExitOnFailure(E_FAIL, "EnumServicesStatusExW failed"); } info = (LPENUM_SERVICE_STATUS_PROCESS)buf; for (ULONG i=0; i < num_services; i++) { SC_HANDLE service= OpenServiceW(scm, info[i].lpServiceName, SERVICE_QUERY_CONFIG); if (!service) continue; WcaLog(LOGMSG_VERBOSE, "Checking Service %S", info[i].lpServiceName); QUERY_SERVICE_CONFIGW *config= (QUERY_SERVICE_CONFIGW *)(void *)config_buffer; DWORD needed; BOOL ok= QueryServiceConfigW(service, config,sizeof(config_buffer), &needed); CloseServiceHandle(service); if (ok) { CheckServiceConfig(servicename, datadir, bindir, info[i].lpServiceName, config); } } LExit: if(scm) CloseServiceHandle(scm); ReleaseStr(servicename); ReleaseStr(datadir); ReleaseStr(bindir); return WcaFinalize(er); }
extern "C" UINT __stdcall CheckServiceUpgrades(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; wchar_t* service= 0; wchar_t* dir= 0; wchar_t installerVersion[MAX_VERSION_PROPERTY_SIZE]; char installDir[MAX_PATH]; DWORD size =MAX_VERSION_PROPERTY_SIZE; int installerMajorVersion, installerMinorVersion, installerPatchVersion; bool upgradableServiceFound=false; hr = WcaInitialize(hInstall, __FUNCTION__); WcaLog(LOGMSG_STANDARD, "Initialized."); if (MsiGetPropertyW(hInstall, L"ProductVersion", installerVersion, &size) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(GetLastError()); ExitOnFailure(hr, "MsiGetPropertyW failed"); } if (swscanf(installerVersion,L"%d.%d.%d", &installerMajorVersion, &installerMinorVersion, &installerPatchVersion) !=3) { assert(FALSE); } size= MAX_PATH; if (MsiGetPropertyA(hInstall,"INSTALLDIR", installDir, &size) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(GetLastError()); ExitOnFailure(hr, "MsiGetPropertyW failed"); } SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT); if (scm == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); ExitOnFailure(hr,"OpenSCManager failed"); } static BYTE buf[64*1024]; static BYTE config_buffer[8*1024]; DWORD bufsize= sizeof(buf); DWORD bufneed; DWORD num_services; BOOL ok= EnumServicesStatusExW(scm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, buf, bufsize, &bufneed, &num_services, NULL, NULL); if(!ok) { hr = HRESULT_FROM_WIN32(GetLastError()); ExitOnFailure(hr,"EnumServicesStatusEx failed"); } LPENUM_SERVICE_STATUS_PROCESSW info = (LPENUM_SERVICE_STATUS_PROCESSW)buf; int index=-1; for (ULONG i=0; i < num_services; i++) { SC_HANDLE service= OpenServiceW(scm, info[i].lpServiceName, SERVICE_QUERY_CONFIG); if (!service) continue; QUERY_SERVICE_CONFIGW *config= (QUERY_SERVICE_CONFIGW*)(void *)config_buffer; DWORD needed; BOOL ok= QueryServiceConfigW(service, config,sizeof(config_buffer), &needed); CloseServiceHandle(service); if (ok) { mysqld_service_properties props; if (get_mysql_service_properties(config->lpBinaryPathName, &props)) continue; /* Only look for services that have mysqld.exe outside of the current installation directory. */ if(installDir[0] == 0 || strstr(props.mysqld_exe,installDir) == 0) { WcaLog(LOGMSG_STANDARD, "found service %S, major=%d, minor=%d", info[i].lpServiceName, props.version_major, props.version_minor); if(props.version_major < installerMajorVersion || (props.version_major == installerMajorVersion && props.version_minor <= installerMinorVersion)) { upgradableServiceFound= true; break; } } } } if(!upgradableServiceFound) { /* Disable optional checkbox at the end of installation */ MsiSetPropertyW(hInstall, L"WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT", L""); MsiSetPropertyW(hInstall, L"WIXUI_EXITDIALOGOPTIONALCHECKBOX",L""); } else { MsiSetPropertyW(hInstall, L"UpgradableServiceFound", L"1"); MsiSetPropertyW(hInstall, L"WIXUI_EXITDIALOGOPTIONALCHECKBOX",L"1"); } LExit: if(scm) CloseServiceHandle(scm); return WcaFinalize(er); }
/******************************************************************** PrintEula - Custom Action entry point ********************************************************************/ extern "C" UINT __stdcall PrintEula(MSIHANDLE hInstall) { //AssertSz(FALSE, "Debug PrintEula"); HRESULT hr = S_OK; HWND hWndMain = NULL; HMODULE hRichEdit = NULL; BOOL fRegisteredClass = FALSE; hr = WcaInitialize(hInstall, "PrintEula"); ExitOnFailure(hr, "failed to initialize"); // Initialize then display print dialog. vpPrintDlg = (PRINTDLGEXW*)GlobalAlloc(GPTR, sizeof(PRINTDLGEXW)); // MSDN says to allocate on heap. ExitOnNullWithLastError(vpPrintDlg, hr, "Failed to allocate memory for print dialog struct."); vpPrintDlg->lStructSize = sizeof(PRINTDLGEX); vpPrintDlg->hwndOwner = ::FindWindowW(L"MsiDialogCloseClass", NULL); vpPrintDlg->Flags = PD_RETURNDC | PD_COLLATE | PD_NOCURRENTPAGE | PD_ALLPAGES | PD_NOPAGENUMS | PD_NOSELECTION; vpPrintDlg->nCopies = NO_OF_COPIES; vpPrintDlg->nStartPage = START_PAGE_GENERAL; hr = ::PrintDlgExW(vpPrintDlg); ExitOnFailure(hr, "Failed to show print dialog"); // If user said they want to print. if (PD_RESULT_PRINT == vpPrintDlg->dwResultAction) { // Get the stream for Eula hr = ReadEulaText(hInstall, &vpszEulaText); ExitOnFailure(hr, "failed to read Eula text from MSI database"); // Have to load Rich Edit since we'll be creating a Rich Edit control in the window hr = LoadSystemLibrary(L"Riched20.dll", &hRichEdit); ExitOnFailure(hr, "failed to load rich edit 2.0 library"); hr = CreateRichTextWindow(&hWndMain, &fRegisteredClass); ExitOnFailure(hr, "failed to create rich text window for printing"); hr = PrintRichText(hWndMain); if (FAILED(hr)) // Since we've already shown the print dialog, we better show them a dialog explaining why it didn't print { ShowErrorMessage(hr); } } LExit: ReleaseNullStr(vpszEulaText); if (vpPrintDlg) { if (vpPrintDlg->hDevMode) { ::GlobalFree(vpPrintDlg->hDevMode); } if (vpPrintDlg->hDevNames) { ::GlobalFree(vpPrintDlg->hDevNames); } if (vpPrintDlg->hDC) { ::DeleteDC(vpPrintDlg->hDC); } ::GlobalFree(vpPrintDlg); vpPrintDlg = NULL; } if (fRegisteredClass) { ::UnregisterClassW(WINDOW_CLASS, NULL); } if (NULL != hRichEdit) { ::FreeLibrary(hRichEdit); } // Always return success since we dont want to stop the // installation even if the Eula printing fails. return WcaFinalize(ERROR_SUCCESS); }
/****************************************************************** RollbackServiceConfig - entry point for ServiceConfig rollback Custom Action. NOTE: CustomActionScript Data == wzServiceName\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\t... *******************************************************************/ extern "C" UINT __stdcall RollbackServiceConfig( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug RollbackServiceConfig"); HRESULT hr = S_OK; DWORD er = 0; LPWSTR pwzCustomActionData = NULL; LPWSTR pwz = NULL; LPWSTR pwzScriptKey = NULL; WCA_CASCRIPT_HANDLE hRollbackScript = NULL; LPWSTR pwzServiceName = NULL; LPWSTR pwzFirstFailureActionType = NULL; LPWSTR pwzSecondFailureActionType = NULL; LPWSTR pwzThirdFailureActionType = NULL; LPWSTR pwzProgramCommandLine = NULL; LPWSTR pwzRebootMessage = NULL; DWORD dwResetPeriodInDays = 0; DWORD dwRestartServiceDelayInSeconds = 0; LPVOID lpMsgBuf = NULL; SC_HANDLE hSCM = NULL; SC_HANDLE hService = NULL; // initialize hr = WcaInitialize(hInstall, "RollbackServiceConfig"); ExitOnFailure(hr, "Failed to initialize 'RollbackServiceConfig'."); // Open the Services Control Manager up front. hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (NULL == hSCM) { er = ::GetLastError(); hr = HRESULT_FROM_WIN32(er); #pragma prefast(push) #pragma prefast(disable:25028) ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); #pragma prefast(pop) ExitOnFailure1(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf); // Make sure we still abort, in case hSCM was NULL but no error was returned from GetLastError ExitOnNull(hSCM, hr, E_POINTER, "Getting handle to SCM reported success, but no handle was returned."); } // Get the script key from the CustomAction data and use it to open // the rollback log and read the data over the CustomActionData // because all of the information is in the script data not the // CustomActionData. hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); if (!pwzScriptKey) { hr = E_UNEXPECTED; ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed."); } ExitOnFailure(hr, "Failed to read encoding key from CustomActionData."); hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); ExitOnFailure(hr, "Failed to open rollback CustomAction script."); hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzCustomActionData); ExitOnFailure(hr, "Failed to read rollback script into CustomAction data."); // Loop through the script's CustomActionData, processing each // service config in turn. pwz = pwzCustomActionData; while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwResetPeriodInDays)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwRestartServiceDelayInSeconds)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); ExitOnFailure(hr, "failed to process CustomActionData"); WcaLog(LOGMSG_VERBOSE, "Reconfiguring Service: %ls", pwzServiceName); // Open the handle with all the permissions we might need. // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2(). // SERVICE_START is required in order to handle SC_ACTION_RESTART action. hr = GetService(hSCM, pwzServiceName, SERVICE_CHANGE_CONFIG | SERVICE_START, &hService); ExitOnFailure1(hr, "Failed to get service: %ls", pwzServiceName); hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType, pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine); ExitOnFailure1(hr, "Failed to configure service: %ls", pwzServiceName); hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); ExitOnFailure(hr, "failed to send progress message"); // Per-service cleanup ::CloseServiceHandle(hService); hService = NULL; dwResetPeriodInDays = 0; dwRestartServiceDelayInSeconds = 0; } LExit: if (lpMsgBuf) // Allocated with FormatString. { ::LocalFree(lpMsgBuf); } if (hService) { ::CloseServiceHandle(hService); } if (hSCM) { ::CloseServiceHandle(hSCM); } WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); ReleaseStr(pwzRebootMessage); ReleaseStr(pwzProgramCommandLine); ReleaseStr(pwzThirdFailureActionType); ReleaseStr(pwzSecondFailureActionType); ReleaseStr(pwzFirstFailureActionType); ReleaseStr(pwzServiceName); ReleaseStr(pwzScriptKey); ReleaseStr(pwzCustomActionData); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
extern "C" UINT __stdcall WixShellExecBinary( __in MSIHANDLE hInstall ) { Assert(hInstall); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzBinary = NULL; LPWSTR pwzFilename = NULL; BYTE* pbData = NULL; DWORD cbData = 0; HANDLE hFile = INVALID_HANDLE_VALUE; #if 0 ::MessageBoxA(0, "WixShellExecBinary", "-->> ATTACH HERE", MB_OK); #endif hr = WcaInitialize(hInstall, "WixShellExecBinary"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetFormattedProperty(L"WixShellExecBinaryId", &pwzBinary); ExitOnFailure(hr, "failed to get WixShellExecBinaryId"); WcaLog(LOGMSG_VERBOSE, "WixShellExecBinaryId is %ls", pwzBinary); if (!pwzBinary || !*pwzBinary) { hr = E_INVALIDARG; ExitOnFailure(hr, "failed to get WixShellExecBinaryId"); } // get temporary path for extracted file StrAlloc(&pwzFilename, MAX_PATH); ExitOnFailure(hr, "Failed to allocate temporary path"); ::GetTempPathW(MAX_PATH, pwzFilename); hr = ::StringCchCatW(pwzFilename, MAX_PATH, pwzBinary); ExitOnFailure(hr, "Failed to append filename."); // grab the bits hr = ExtractBinary(pwzBinary, &pbData, &cbData); ExitOnFailure(hr, "failed to extract binary data"); // write 'em to the temp file hFile = ::CreateFileW(pwzFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { ExitWithLastError1(hr, "Failed to open new temp file: %ls", pwzFilename); } DWORD cbWritten = 0; if (!::WriteFile(hFile, pbData, cbData, &cbWritten, NULL)) { ExitWithLastError1(hr, "Failed to write data to new temp file: %ls", pwzFilename); } // close it ::CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; // and run it hr = ShellExec(pwzFilename); ExitOnFailure1(hr, "failed to launch target: %ls", pwzFilename); LExit: ReleaseStr(pwzBinary); ReleaseStr(pwzFilename); ReleaseMem(pbData); if (INVALID_HANDLE_VALUE != hFile) { ::CloseHandle(hFile); } if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/******************************************************************** ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings ********************************************************************/ extern "C" UINT __stdcall ConfigureIIs( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ConfigureIIs here"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzScriptKey = NULL; LPWSTR pwzBackupId = NULL; LPWSTR pwzCustomActionData = NULL; // CustomActionData for ConfigureIIs custom action // initialize hr = WcaInitialize(hInstall, "ConfigureIIs"); ExitOnFailure(hr, "Failed to initialize"); // check for the prerequsite tables if (S_OK != WcaTableExists(L"IIsWebSite") && S_OK != WcaTableExists(L"IIsFilter") && S_OK != WcaTableExists(L"IIsProperty") && S_OK != WcaTableExists(L"IIsWebServiceExtension") && S_OK != WcaTableExists(L"IIsAppPool")) { WcaLog(LOGMSG_VERBOSE, "skipping IIs CustomAction, no IIsWebSite table, no IIsFilter table, no IIsProperty table, no IIsWebServiceExtension, and no IIsAppPool table"); ExitFunction1(hr = S_FALSE); } // Get a CaScript key hr = WcaCaScriptCreateKey(&pwzScriptKey); ExitOnFailure(hr, "Failed to get encoding key."); // Generate a unique string to be used for this product's transaction // This prevents a name collision when doing a major upgrade hr = WcaGetProperty(L"ProductCode", &pwzBackupId); ExitOnFailure(hr, "failed to get ProductCode"); hr = StrAllocConcat(&pwzBackupId, L"ScaConfigureIIs", 0); ExitOnFailure(hr, "failed to concat ScaConfigureIIs"); // make sure the operations below are wrapped in a "transaction" // use IIS7 transaction logic even if using Iis6 compat because Backup/Restore don't work with metabase compatibility if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, IIS7CONDITION)) { hr = ScaIIS7ConfigTransaction(pwzBackupId); MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS7 transaction"); } else { hr = ScaMetabaseTransaction(pwzBackupId); MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS transaction"); } // Write the CaScript key to the ConfigureIIS custom action data hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add encoding key to CustomActionData."); // Wrap vcsUserDeferredQuery to send to deferred CA if (S_OK == WcaTableExists(L"User")) { hr = WcaWrapQuery(vcsUserDeferredQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap User query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap User empty query"); } // Wrap vcsWebSvcExtQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebServiceExtension")) { hr = WcaWrapQuery(vcsWebSvcExtQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4, 1, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension empty query"); } // Wrap vcsAppPoolQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsAppPool")) { hr = WcaWrapQuery(vcsAppPoolQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn15 | efmcColumn16, 3, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsAppPool query"); hr = WcaWrapQuery(vcsComponentAttrQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap Component query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsAppPool empty query"); } // Wrap vcsMimeMapQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsMimeMap")) { hr = WcaWrapQuery(vcsMimeMapQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsMimeMap query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsMimeMap empty query"); } // Wrap vcsHttpHeaderQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsHttpHeader")) { hr = WcaWrapQuery(vcsHttpHeaderQuery, &pwzCustomActionData, efmcColumn1 | efmcColumn4, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsHttpHeader query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsHttpHeader empty query"); } // Wrap vcsWebErrorQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebError")) { hr = WcaWrapQuery(vcsWebErrorQuery, &pwzCustomActionData, efmcColumn5 | efmcColumn6, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebError query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebError empty query"); } // Wrap vcsWebDirPropertiesQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebDirProperties")) { hr = WcaWrapQuery(vcsWebDirPropertiesQuery, &pwzCustomActionData, efmcColumn8 | efmcColumn10 | efmcColumn12 | efmcColumn15, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties empty query"); } // Wrap vcsSslCertificateQuery to send to deferred CA if (S_OK == WcaTableExists(L"Certificate") && S_OK == WcaTableExists(L"CertificateHash") && S_OK == WcaTableExists(L"IIsWebSiteCertificates")) { hr = WcaWrapQuery(vcsSslCertificateQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap SslCertificate query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap SslCertificate empty query"); } // Wrap vcsWebLogQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebLog")) { hr = WcaWrapQuery(vcsWebLogQuery, &pwzCustomActionData, efmcColumn2, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebLog query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebLog empty query"); } // Wrap vcsWebApplicationQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebApplication")) { hr = WcaWrapQuery(vcsWebApplicationQuery, &pwzCustomActionData, efmcColumn1, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebApplication query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebApplication empty query"); } // Wrap vcsWebAppExtensionQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebApplicationExtension")) { hr = WcaWrapQuery(vcsWebAppExtensionQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension empty query"); } // Wrap vcsWebQuery, vcsWebAddressQuery, and vcsWebBaseQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebAddress") && S_OK == WcaTableExists(L"IIsWebSite")) { hr = WcaWrapQuery(vcsWebQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn12 | efmcColumn13 | efmcColumn14, 2, 6); ExitOnFailure(hr, "Failed to wrap IIsWebSite query"); hr = WcaWrapQuery(vcsWebAddressQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebAddress query"); hr = WcaWrapQuery(vcsWebBaseQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4 | efmcColumn5 | efmcColumn7, 0xFFFFFFFF, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebBase query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebSite empty query"); hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebAddress empty query"); hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebBase empty query"); } // Wrap vcsWebDirQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebDir")) { hr = WcaWrapQuery(vcsWebDirQuery, &pwzCustomActionData, efmcColumn4, 3, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsWebDir query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebDir empty query"); } // Wrap vcsVDirQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsWebVirtualDir")) { hr = WcaWrapQuery(vcsVDirQuery, &pwzCustomActionData, efmcColumn4, 3, 5); ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir empty query"); } // Wrap vcsFilterQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsFilter")) { hr = WcaWrapQuery(vcsFilterQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 3, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsFilter query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsFilter empty query"); } // Wrap vcsPropertyQuery to send to deferred CA if (S_OK == WcaTableExists(L"IIsProperty")) { hr = WcaWrapQuery(vcsPropertyQuery, &pwzCustomActionData, efmcColumn4, 2, 0xFFFFFFFF); ExitOnFailure(hr, "Failed to wrap IIsProperty query"); } else { hr = WcaWrapEmptyQuery(&pwzCustomActionData); ExitOnFailure(hr, "Failed to wrap IIsProperty empty query"); } if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, USEIIS7CONDITION)) { // This must remain trace only, CA data may contain password WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIIS7Exec will be: %ls", pwzCustomActionData); hr = WcaDoDeferredAction(L"ConfigureIIs7Exec", pwzCustomActionData, ConfigureIIsCost); ExitOnFailure(hr, "Failed to schedule ConfigureIIs7Exec custom action"); ReleaseNullStr(pwzCustomActionData); // Write the CaScript key to the ConfigureIIS custom action data hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add script key to CustomActionData."); hr = WcaDoDeferredAction(L"WriteIIS7ConfigChanges", pwzCustomActionData, WriteIIS7ConfigChangesCost); ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action"); } else { // This must remain trace only, CA data may contain password WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIISExec will be: %ls", pwzCustomActionData); hr = WcaDoDeferredAction(L"ConfigureIIsExec", pwzCustomActionData, ConfigureIIsCost); ExitOnFailure(hr, "Failed to schedule ConfigureIISExec custom action"); ReleaseNullStr(pwzCustomActionData); // Write the CaScript key to the ConfigureIIS custom action data hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add script key to CustomActionData."); hr = WcaDoDeferredAction(L"WriteMetabaseChanges", pwzCustomActionData, WriteMetabaseChangesCost); ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action"); } LExit: ReleaseStr(pwzScriptKey); ReleaseStr(pwzBackupId); ReleaseStr(pwzCustomActionData); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/******************************************************************** ConfigurePerfmonManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling Perfmon counter manifest registering ********************************************************************/ extern "C" UINT __stdcall ConfigurePerfmonManifestRegister( __in MSIHANDLE hInstall ) { HRESULT hr; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; LPWSTR pwzData = NULL, pwzResourceFilePath = NULL, pwzFile = NULL, pwzCommand = NULL; INSTALLSTATE isInstalled, isAction; hr = WcaInitialize(hInstall, "ConfigurePerfmonManifestReg"); ExitOnFailure(hr, "Failed to initialize"); if (!IsVistaOrAbove()) { WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestRegister() because the target system does not support perfmon manifest"); ExitFunction1(hr = S_FALSE); } // check to see if necessary tables are specified if (S_OK != WcaTableExists(L"PerfmonManifest")) { WcaLog(LOGMSG_VERBOSE, "Skipping ConfigurePerfmonManifestRegister() because PerfmonManifest table not present"); ExitFunction1(hr = S_FALSE); } hr = WcaOpenExecuteView(vcsPerfmonManifestQuery, &hView); ExitOnFailure(hr, "failed to open view on PerfMonManifest table"); while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) { // get component install state hr = WcaGetRecordString(hRec, pfmComponent, &pwzData); ExitOnFailure(hr, "failed to get Component for PerfMonManifest"); er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); hr = HRESULT_FROM_WIN32(er); ExitOnFailure(hr, "failed to get Component state for PerfMonManifest"); if (!WcaIsInstalling(isInstalled, isAction)) { continue; } hr = WcaGetRecordFormattedString(hRec, pfmFile, &pwzFile); ExitOnFailure(hr, "failed to get File for PerfMonManifest"); hr = WcaGetRecordFormattedString(hRec, pfmResourceFileDir, &pwzResourceFilePath); ExitOnFailure(hr, "failed to get ApplicationIdentity for PerfMonManifest"); size_t iResourcePath = lstrlenW(pwzResourceFilePath); if ( iResourcePath > 0 && *(pwzResourceFilePath + iResourcePath -1) == L'\\') *(pwzResourceFilePath + iResourcePath -1) = 0; //remove the trailing '\' hr = StrAllocFormatted(&pwzCommand, L"\"unlodctr.exe\" /m:\"%s\"", pwzFile); ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"RollbackRegisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); ExitOnFailure(hr, "failed to schedule RollbackRegisterPerfmonManifest action"); if ( *pwzResourceFilePath ) { hr = StrAllocFormatted(&pwzCommand, L"\"lodctr.exe\" /m:\"%s\" \"%s\"", pwzFile, pwzResourceFilePath); ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); } else { hr = StrAllocFormatted(&pwzData, L"\"lodctr.exe\" /m:\"%s\"", pwzFile); ExitOnFailure(hr, "failed to copy string in PerfMonManifest"); } WcaLog(LOGMSG_VERBOSE, "RegisterPerfmonManifest's CustomActionData: '%ls'", pwzCommand); hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"RegisterPerfmonManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER); ExitOnFailure(hr, "failed to schedule RegisterPerfmonManifest action"); } if (hr == E_NOMOREITEMS) { hr = S_OK; } ExitOnFailure(hr, "Failure while processing PerfMonManifest"); hr = S_OK; LExit: ReleaseStr(pwzData); ReleaseStr(pwzResourceFilePath); ReleaseStr(pwzFile); ReleaseStr(pwzCommand); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/******************************************************************** ConfigureComPlusInstall - CUSTOM ACTION ENTRY POINT for installing COM+ components ********************************************************************/ extern "C" UINT __stdcall ConfigureComPlusInstall(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; BOOL fInitializedCom = FALSE; ICOMAdminCatalog* piCatalog = NULL; CPI_PARTITION_LIST partList; CPI_PARTITION_ROLE_LIST partRoleList; CPI_USER_IN_PARTITION_ROLE_LIST usrInPartRoleList; CPI_PARTITION_USER_LIST partUsrList; CPI_APPLICATION_LIST appList; CPI_APPLICATION_ROLE_LIST appRoleList; CPI_USER_IN_APPLICATION_ROLE_LIST usrInAppRoleList; CPI_ASSEMBLY_LIST asmList; CPI_SUBSCRIPTION_LIST subList; LPWSTR pwzRollbackFileName = NULL; LPWSTR pwzActionData = NULL; LPWSTR pwzRollbackActionData = NULL; LPWSTR pwzCommitActionData = NULL; int iVersionNT = 0; int iProgress = 0; int iCommitProgress = 0; ::ZeroMemory(&partList, sizeof(CPI_PARTITION_LIST)); ::ZeroMemory(&partRoleList, sizeof(CPI_PARTITION_ROLE_LIST)); ::ZeroMemory(&usrInPartRoleList, sizeof(CPI_USER_IN_PARTITION_ROLE_LIST)); ::ZeroMemory(&partUsrList, sizeof(CPI_PARTITION_USER_LIST)); ::ZeroMemory(&appList, sizeof(CPI_APPLICATION_LIST)); ::ZeroMemory(&appRoleList, sizeof(CPI_APPLICATION_ROLE_LIST)); ::ZeroMemory(&usrInAppRoleList, sizeof(CPI_USER_IN_APPLICATION_ROLE_LIST)); ::ZeroMemory(&asmList, sizeof(CPI_ASSEMBLY_LIST)); ::ZeroMemory(&subList, sizeof(CPI_SUBSCRIPTION_LIST)); // initialize hr = WcaInitialize(hInstall, "ConfigureComPlusInstall"); ExitOnFailure(hr, "Failed to initialize"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; CpiInitialize(); // check for the prerequsite tables if (!CpiTableExists(cptComPlusPartition) && !CpiTableExists(cptComPlusApplication) && !CpiTableExists(cptComPlusAssembly)) { WcaLog(LOGMSG_VERBOSE, "skipping install COM+ CustomAction, no ComPlusPartition, ComPlusApplication or ComPlusAssembly table present"); ExitFunction1(hr = S_FALSE); } // make sure we can access the COM+ admin catalog do { hr = CpiGetAdminCatalog(&piCatalog); if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "Failed to get COM+ admin catalog"); er = WcaErrorMessage(msierrComPlusCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction(); // exit with hr from CpiGetAdminCatalog() to kick off a rollback case IDRETRY: hr = S_FALSE; break; case IDIGNORE: default: ExitFunction1(hr = S_OK); // pretend everything is okay and bail } } } while (S_FALSE == hr); // get NT version hr = WcaGetIntProperty(L"VersionNT", &iVersionNT); ExitOnFailure(hr, "Failed to get VersionNT property"); // read elements if (502 <= iVersionNT && CpiTableExists(cptComPlusPartition)) { hr = CpiPartitionsRead(&partList); MessageExitOnFailure(hr, msierrComPlusPartitionReadFailed, "Failed to read ComPlusPartitions table"); } if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionRole)) { hr = CpiPartitionRolesRead(&partList, &partRoleList); MessageExitOnFailure(hr, msierrComPlusPartitionRoleReadFailed, "Failed to read ComPlusPartitionRole table"); } if (502 <= iVersionNT && (CpiTableExists(cptComPlusUserInPartitionRole) || CpiTableExists(cptComPlusGroupInPartitionRole))) { hr = CpiUsersInPartitionRolesRead(&partRoleList, &usrInPartRoleList); MessageExitOnFailure(hr, msierrComPlusUserInPartitionRoleReadFailed, "Failed to read ComPlusUserInPartitionRole table"); } if (502 <= iVersionNT && CpiTableExists(cptComPlusPartitionUser)) { hr = CpiPartitionUsersRead(&partList, &partUsrList); MessageExitOnFailure(hr, msierrComPlusPartitionUserReadFailed, "Failed to read ComPlusPartitionUser table"); } if (CpiTableExists(cptComPlusApplication)) { hr = CpiApplicationsRead(&partList, &appList); MessageExitOnFailure(hr, msierrComPlusApplicationReadFailed, "Failed to read ComPlusApplication table"); } if (CpiTableExists(cptComPlusApplicationRole)) { hr = CpiApplicationRolesRead(&appList, &appRoleList); MessageExitOnFailure(hr, msierrComPlusApplicationRoleReadFailed, "Failed to read ComPlusApplicationRole table"); } if (CpiTableExists(cptComPlusUserInApplicationRole) || CpiTableExists(cptComPlusGroupInApplicationRole)) { hr = CpiUsersInApplicationRolesRead(&appRoleList, &usrInAppRoleList); MessageExitOnFailure(hr, msierrComPlusUserInApplicationRoleReadFailed, "Failed to read ComPlusUserInApplicationRole table"); } if (CpiTableExists(cptComPlusAssembly)) { hr = CpiAssembliesRead(&appList, &appRoleList, &asmList); MessageExitOnFailure(hr, msierrComPlusAssembliesReadFailed, "Failed to read ComPlusAssembly table"); } if (CpiTableExists(cptComPlusSubscription)) { hr = CpiSubscriptionsRead(&asmList, &subList); MessageExitOnFailure(hr, msierrComPlusSubscriptionReadFailed, "Failed to read ComPlusSubscription table"); } // verify elements hr = CpiPartitionsVerifyInstall(&partList); ExitOnFailure(hr, "Failed to verify partitions"); hr = CpiApplicationsVerifyInstall(&appList); ExitOnFailure(hr, "Failed to verify applications"); hr = CpiApplicationRolesVerifyInstall(&appRoleList); ExitOnFailure(hr, "Failed to verify application roles"); hr = CpiAssembliesVerifyInstall(&asmList); ExitOnFailure(hr, "Failed to verify assemblies"); if (subList.iInstallCount) { hr = CpiSubscriptionsVerifyInstall(&subList); ExitOnFailure(hr, "Failed to verify subscriptions"); } // schedule if (partList.iInstallCount || appList.iInstallCount || usrInAppRoleList.iInstallCount || appRoleList.iInstallCount || asmList.iInstallCount || asmList.iRoleInstallCount || subList.iInstallCount) { // create rollback file name hr = CpiGetTempFileName(&pwzRollbackFileName); ExitOnFailure(hr, "Failed to get rollback file name"); // schedule rollback prepare custom action hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLPREPARE, pwzRollbackFileName, 0); ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallPrepare"); // schedule prepare custom action hr = WcaDoDeferredAction(CP_COMPLUSINSTALLPREPARE, pwzRollbackFileName, 0); ExitOnFailure(hr, "Failed to schedule ComPlusInstallPrepare"); // schedule rollback custom action hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzRollbackActionData); ExitOnFailure(hr, "Failed to add rollback file name to rollback custom action data"); hr = CpiSubscriptionsInstall(&subList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install subscriptions"); hr = CpiRoleAssignmentsInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiAssembliesInstall(&asmList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install users in application roles"); hr = CpiApplicationRolesInstall(&appRoleList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install application roles"); hr = CpiApplicationsInstall(&appList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install applications"); hr = CpiPartitionUsersInstall(&partUsrList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install partition users"); hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install users in partition roles"); hr = CpiPartitionsInstall(&partList, rmRollback, &pwzRollbackActionData, NULL); ExitOnFailure(hr, "Failed to install partitions"); hr = WcaDoDeferredAction(CP_COMPLUSROLLBACKINSTALLEXECUTE, pwzRollbackActionData, 0); ExitOnFailure(hr, "Failed to schedule ComPlusRollbackInstallExecute"); // schedule install custom action hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzActionData); ExitOnFailure(hr, "Failed to add rollback file name to custom action data"); hr = CpiPartitionsInstall(&partList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install partitions"); hr = CpiUsersInPartitionRolesInstall(&usrInPartRoleList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install users in partition roles"); hr = CpiPartitionUsersInstall(&partUsrList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install partition users"); hr = CpiApplicationsInstall(&appList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install applications"); hr = CpiApplicationRolesInstall(&appRoleList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install application roles"); hr = CpiUsersInApplicationRolesInstall(&usrInAppRoleList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install users in application roles"); hr = CpiAssembliesInstall(&asmList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiRoleAssignmentsInstall(&asmList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiSubscriptionsInstall(&subList, rmDeferred, &pwzActionData, &iProgress); ExitOnFailure(hr, "Failed to install subscriptions"); hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTE, pwzActionData, iProgress); ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecute"); // schedule install commit custom action hr = WcaWriteStringToCaData(pwzRollbackFileName, &pwzCommitActionData); ExitOnFailure(hr, "Failed to add rollback file name to commit custom action data"); hr = CpiAssembliesInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiRoleAssignmentsInstall(&asmList, rmCommit, &pwzCommitActionData, &iCommitProgress); ExitOnFailure(hr, "Failed to install assemblies"); hr = CpiSubscriptionsInstall(&subList, rmCommit, &pwzCommitActionData, &iCommitProgress); ExitOnFailure(hr, "Failed to install subscriptions"); hr = WcaDoDeferredAction(CP_COMPLUSINSTALLEXECUTECOMMIT, pwzCommitActionData, iCommitProgress); ExitOnFailure(hr, "Failed to schedule ComPlusInstallExecuteCommit"); // schedule commit custom action hr = WcaDoDeferredAction(CP_COMPLUSINSTALLCOMMIT, pwzRollbackFileName, 0); ExitOnFailure(hr, "Failed to schedule ComPlusInstallCommit"); } hr = S_OK; LExit: // clean up ReleaseObject(piCatalog); ReleaseStr(pwzRollbackFileName); ReleaseStr(pwzActionData); ReleaseStr(pwzRollbackActionData); ReleaseStr(pwzCommitActionData); CpiPartitionListFree(&partList); CpiPartitionRoleListFree(&partRoleList); CpiUserInPartitionRoleListFree(&usrInPartRoleList); CpiPartitionUserListFree(&partUsrList); CpiApplicationListFree(&appList); CpiApplicationRoleListFree(&appRoleList); CpiUserInApplicationRoleListFree(&usrInAppRoleList); CpiAssemblyListFree(&asmList); CpiSubscriptionListFree(&subList); // unitialize CpiFinalize(); if (fInitializedCom) ::CoUninitialize(); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/******************************************************************** ConfigureEventManifestRegister - CUSTOM ACTION ENTRY POINT for scheduling Event manifest registering ********************************************************************/ extern "C" UINT __stdcall ConfigureEventManifestUnregister( __in MSIHANDLE hInstall ) { HRESULT hr; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; LPWSTR pwzData = NULL, pwzFile = NULL, pwzCommand = NULL; INSTALLSTATE isInstalled, isAction; hr = WcaInitialize(hInstall, "ConfigureEventManifestUnreg"); ExitOnFailure(hr, "Failed to initialize"); if (!IsVistaOrAbove()) { WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestUnregister() because the target system does not support event manifest"); ExitFunction1(hr = S_FALSE); } // check to see if necessary tables are specified if (S_OK != WcaTableExists(L"EventManifest")) { WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureEventManifestUnregister() because EventManifest table not present"); ExitFunction1(hr = S_FALSE); } hr = WcaOpenExecuteView(vcsEventManifestQuery, &hView); ExitOnFailure(hr, "failed to open view on EventManifest table"); while ((hr = WcaFetchRecord(hView, &hRec)) == S_OK) { // get component install state hr = WcaGetRecordString(hRec, emComponent, &pwzData); ExitOnFailure(hr, "failed to get Component for EventManifest"); er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); hr = HRESULT_FROM_WIN32(er); ExitOnFailure(hr, "failed to get Component state for EventManifest"); // nothing to do on an install // schedule the rollback action when reinstalling to re-register pre-patch manifest if (!WcaIsUninstalling(isInstalled, isAction) && !WcaIsReInstalling(isInstalled, isAction)) { continue; } hr = WcaGetRecordFormattedString(hRec, emFile, &pwzFile); ExitOnFailure(hr, "failed to get File for EventManifest"); hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" im \"%s\"", pwzFile); ExitOnFailure(hr, "failed to copy string in EventManifest"); hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"RollbackUnregisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_REGISTER); ExitOnFailure(hr, "failed to schedule RollbackUnregisterEventManifest action"); // no need to uninstall on a repair/patch. Register action will re-register and update the manifest. if (!WcaIsReInstalling(isInstalled, isAction)) { hr = StrAllocFormatted(&pwzCommand, L"\"wevtutil.exe\" um \"%s\"", pwzFile); ExitOnFailure(hr, "failed to copy string in EventManifest"); WcaLog(LOGMSG_VERBOSE, "UnregisterEventManifest's CustomActionData: '%ls'", pwzCommand); hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"UnregisterEventManifest"), pwzCommand, COST_PERFMONMANIFEST_UNREGISTER); ExitOnFailure(hr, "failed to schedule UnregisterEventManifest action"); } } if (hr == E_NOMOREITEMS) { hr = S_OK; } ExitOnFailure(hr, "Failure while processing EventManifest"); hr = S_OK; LExit: ReleaseStr(pwzData); ReleaseStr(pwzFile); ReleaseStr(pwzCommand); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
extern "C" UINT WINAPI WixRemoveFoldersEx( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug WixRemoveFoldersEx"); HRESULT hr = S_OK; PMSIHANDLE hView; PMSIHANDLE hRec; LPWSTR sczId = NULL; LPWSTR sczComponent = NULL; LPWSTR sczProperty = NULL; LPWSTR sczPath = NULL; LPWSTR sczExpandedPath = NULL; int iMode = 0; DWORD dwCounter = 0; DWORD_PTR cchLen = 0; MSIHANDLE hTable = NULL; MSIHANDLE hColumns = NULL; hr = WcaInitialize(hInstall, "WixRemoveFoldersEx"); ExitOnFailure(hr, "Failed to initialize WixRemoveFoldersEx."); // anything to do? if (S_OK != WcaTableExists(L"WixRemoveFolderEx")) { WcaLog(LOGMSG_STANDARD, "WixRemoveFolderEx table doesn't exist, so there are no folders to remove."); ExitFunction(); } // query and loop through all the remove folders exceptions hr = WcaOpenExecuteView(vcsRemoveFolderExQuery, &hView); ExitOnFailure(hr, "Failed to open view on WixRemoveFolderEx table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hr = WcaGetRecordString(hRec, rfqId, &sczId); ExitOnFailure(hr, "Failed to get remove folder identity."); hr = WcaGetRecordString(hRec, rfqComponent, &sczComponent); ExitOnFailure(hr, "Failed to get remove folder component."); hr = WcaGetRecordString(hRec, rfqProperty, &sczProperty); ExitOnFailure(hr, "Failed to get remove folder property."); hr = WcaGetRecordInteger(hRec, feqMode, &iMode); ExitOnFailure(hr, "Failed to get remove folder mode"); hr = WcaGetProperty(sczProperty, &sczPath); ExitOnFailure2(hr, "Failed to resolve remove folder property: %S for row: %S", sczProperty, sczId); // fail early if the property isn't set as you probably don't want your installers trying to delete SystemFolder // StringCchLengthW succeeds only if the string is zero characters plus 1 for the terminating null hr = ::StringCchLengthW(sczPath, 1, reinterpret_cast<UINT_PTR*>(&cchLen)); if (SUCCEEDED(hr)) { ExitOnFailure2(hr = E_INVALIDARG, "Missing folder property: %S for row: %S", sczProperty, sczId); } hr = PathExpand(&sczExpandedPath, sczPath, PATH_EXPAND_ENVIRONMENT); ExitOnFailure2(hr, "Failed to expand path: %S for row: %S", sczPath, sczId); hr = PathBackslashTerminate(&sczExpandedPath); ExitOnFailure1(hr, "Failed to backslash-terminate path: %S", sczExpandedPath); WcaLog(LOGMSG_STANDARD, "Recursing path: %S for row: %S.", sczExpandedPath, sczId); hr = RecursePath(sczExpandedPath, sczId, sczComponent, sczProperty, iMode, &dwCounter, &hTable, &hColumns); ExitOnFailure2(hr, "Failed while navigating path: %S for row: %S", sczPath, sczId); } // reaching the end of the list is actually a good thing, not an error if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "Failure occured while processing WixRemoveFolderEx table"); LExit: if (hColumns) { ::MsiCloseHandle(hColumns); } if (hTable) { ::MsiCloseHandle(hTable); } ReleaseStr(sczExpandedPath); ReleaseStr(sczPath); ReleaseStr(sczProperty); ReleaseStr(sczComponent); ReleaseStr(sczId); DWORD er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/******************************************************************** WixQueryOsInfo - entry point for WixQueryOsInfo custom action Called as Type 1 custom action (DLL from the Binary table) from Windows Installer to set properties that identify OS information and predefined directories ********************************************************************/ extern "C" UINT __stdcall WixQueryOsInfo( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; OSVERSIONINFOEXW ovix = {0}; hr = WcaInitialize(hInstall, "WixQueryOsInfo"); ExitOnFailure(hr, "WixQueryOsInfo failed to initialize"); // identify product suites ovix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); ::GetVersionExW(reinterpret_cast<LPOSVERSIONINFOW>(&ovix)); if (VER_SUITE_SMALLBUSINESS == (ovix.wSuiteMask & VER_SUITE_SMALLBUSINESS)) { WcaSetIntProperty(L"WIX_SUITE_SMALLBUSINESS", 1); } if (VER_SUITE_ENTERPRISE == (ovix.wSuiteMask & VER_SUITE_ENTERPRISE)) { WcaSetIntProperty(L"WIX_SUITE_ENTERPRISE", 1); } if (VER_SUITE_BACKOFFICE == (ovix.wSuiteMask & VER_SUITE_BACKOFFICE)) { WcaSetIntProperty(L"WIX_SUITE_BACKOFFICE", 1); } if (VER_SUITE_COMMUNICATIONS == (ovix.wSuiteMask & VER_SUITE_COMMUNICATIONS)) { WcaSetIntProperty(L"WIX_SUITE_COMMUNICATIONS", 1); } if (VER_SUITE_TERMINAL == (ovix.wSuiteMask & VER_SUITE_TERMINAL)) { WcaSetIntProperty(L"WIX_SUITE_TERMINAL", 1); } if (VER_SUITE_SMALLBUSINESS_RESTRICTED == (ovix.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)) { WcaSetIntProperty(L"WIX_SUITE_SMALLBUSINESS_RESTRICTED", 1); } if (VER_SUITE_EMBEDDEDNT == (ovix.wSuiteMask & VER_SUITE_EMBEDDEDNT)) { WcaSetIntProperty(L"WIX_SUITE_EMBEDDEDNT", 1); } if (VER_SUITE_DATACENTER == (ovix.wSuiteMask & VER_SUITE_DATACENTER)) { WcaSetIntProperty(L"WIX_SUITE_DATACENTER", 1); } if (VER_SUITE_SINGLEUSERTS == (ovix.wSuiteMask & VER_SUITE_SINGLEUSERTS)) { WcaSetIntProperty(L"WIX_SUITE_SINGLEUSERTS", 1); } if (VER_SUITE_PERSONAL == (ovix.wSuiteMask & VER_SUITE_PERSONAL)) { WcaSetIntProperty(L"WIX_SUITE_PERSONAL", 1); } if (VER_SUITE_BLADE == (ovix.wSuiteMask & VER_SUITE_BLADE)) { WcaSetIntProperty(L"WIX_SUITE_BLADE", 1); } if (VER_SUITE_EMBEDDED_RESTRICTED == (ovix.wSuiteMask & VER_SUITE_EMBEDDED_RESTRICTED)) { WcaSetIntProperty(L"WIX_SUITE_EMBEDDED_RESTRICTED", 1); } if (VER_SUITE_SECURITY_APPLIANCE == (ovix.wSuiteMask & VER_SUITE_SECURITY_APPLIANCE)) { WcaSetIntProperty(L"WIX_SUITE_SECURITY_APPLIANCE", 1); } if (VER_SUITE_STORAGE_SERVER == (ovix.wSuiteMask & VER_SUITE_STORAGE_SERVER)) { WcaSetIntProperty(L"WIX_SUITE_STORAGE_SERVER", 1); } if (VER_SUITE_COMPUTE_SERVER == (ovix.wSuiteMask & VER_SUITE_COMPUTE_SERVER)) { WcaSetIntProperty(L"WIX_SUITE_COMPUTE_SERVER", 1); } if (VER_SUITE_WH_SERVER == (ovix.wSuiteMask & VER_SUITE_WH_SERVER)) { WcaSetIntProperty(L"WIX_SUITE_WH_SERVER", 1); } // only for XP and later if (5 < ovix.dwMajorVersion || (5 == ovix.dwMajorVersion && 0 < ovix.dwMinorVersion)) { if (::GetSystemMetrics(SM_SERVERR2)) { WcaSetIntProperty(L"WIX_SUITE_SERVERR2", 1); } if (::GetSystemMetrics(SM_MEDIACENTER)) { WcaSetIntProperty(L"WIX_SUITE_MEDIACENTER", 1); } if (::GetSystemMetrics(SM_STARTER)) { WcaSetIntProperty(L"WIX_SUITE_STARTER", 1); } if (::GetSystemMetrics(SM_TABLETPC)) { WcaSetIntProperty(L"WIX_SUITE_TABLETPC", 1); } } LExit: if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** CaExecSecureObjects - entry point for SecureObjects Custom Action called as Type 1025 CustomAction (deferred binary DLL) NOTE: deferred CustomAction since it modifies the machine NOTE: CustomActionData == wzObject\twzTable\twzDomain\twzUser\tdwPermissions\twzObject\t... ******************************************************************/ extern "C" UINT __stdcall ExecSecureObjects( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug ExecSecureObjects"); HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; LPWSTR pwz = NULL; LPWSTR pwzData = NULL; LPWSTR pwzObject = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzDomain = NULL; DWORD dwRevision = 0; LPWSTR pwzUser = NULL; DWORD dwPermissions = 0; LPWSTR pwzAccount = NULL; PSID psid = NULL; EXPLICIT_ACCESSW ea = {0}; SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; PSECURITY_DESCRIPTOR psd = NULL; SECURITY_DESCRIPTOR_CONTROL sdc = {0}; SECURITY_INFORMATION si = {0}; PACL pAclExisting = NULL; // doesn't get freed PACL pAclNew = NULL; PMSIHANDLE hActionRec = ::MsiCreateRecord(1); // // initialize // hr = WcaInitialize(hInstall, "ExecSecureObjects"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty(L"CustomActionData", &pwzData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); pwz = pwzData; // // loop through all the passed in data // while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzObject); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzTable); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzDomain); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzUser); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwPermissions)); ExitOnFailure(hr, "failed to processCustomActionData"); WcaLog(LOGMSG_VERBOSE, "Securing Object: %ls Type: %ls User: %ls", pwzObject, pwzTable, pwzUser); // // create the appropriate SID // // figure out the right user to put into the access block if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Everyone")) { hr = AclGetWellKnownSid(WinWorldSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Administrators")) { hr = AclGetWellKnownSid(WinBuiltinAdministratorsSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalSystem")) { hr = AclGetWellKnownSid(WinLocalSystemSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"LocalService")) { hr = AclGetWellKnownSid(WinLocalServiceSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"NetworkService")) { hr = AclGetWellKnownSid(WinNetworkServiceSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"AuthenticatedUser")) { hr = AclGetWellKnownSid(WinAuthenticatedUserSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Guests")) { hr = AclGetWellKnownSid(WinBuiltinGuestsSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"CREATOR OWNER")) { hr = AclGetWellKnownSid(WinCreatorOwnerSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"INTERACTIVE")) { hr = AclGetWellKnownSid(WinInteractiveSid, &psid); } else if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Users")) { hr = AclGetWellKnownSid(WinBuiltinUsersSid, &psid); } else { hr = StrAllocFormatted(&pwzAccount, L"%s%s%s", pwzDomain, *pwzDomain ? L"\\" : L"", pwzUser); ExitOnFailure(hr, "failed to build domain user name"); hr = AclGetAccountSid(NULL, pwzAccount, &psid); } ExitOnFailure3(hr, "failed to get sid for account: %ls%ls%ls", pwzDomain, *pwzDomain ? L"\\" : L"", pwzUser); // // build up the explicit access // ea.grfAccessMode = SET_ACCESS; if (0 == lstrcmpW(L"CreateFolder", pwzTable)) { ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; } else { ea.grfInheritance = NO_INHERITANCE; } #pragma prefast(push) #pragma prefast(disable:25029) ::BuildTrusteeWithSidW(&ea.Trustee, psid); #pragma prefast(pop) objectType = SEObjectTypeFromString(const_cast<LPCWSTR> (pwzTable)); // always add these permissions for services // these are basic permissions that are often forgotten if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) { dwPermissions |= SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_INTERROGATE; } ea.grfAccessPermissions = dwPermissions; if (SE_UNKNOWN_OBJECT_TYPE != objectType) { er = ::GetNamedSecurityInfoW(pwzObject, objectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pAclExisting, NULL, &psd); ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get security info for object: %ls", pwzObject); //Need to see if DACL is protected so getting Descriptor information if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) { ExitOnLastError1(hr, "failed to get security descriptor control for object: %ls", pwzObject); } #pragma prefast(push) #pragma prefast(disable:25029) er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclNew); #pragma prefast(pop) ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to add ACLs for object: %ls", pwzObject); if (sdc & SE_DACL_PROTECTED) { si = DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION; } else { si = DACL_SECURITY_INFORMATION; } er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pAclNew, NULL); MessageExitOnFailure1(hr = HRESULT_FROM_WIN32(er), msierrSecureObjectsFailedSet, "failed to set security info for object: %ls", pwzObject); } else { MessageExitOnFailure1(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); } hr = WcaProgressMessage(COST_SECUREOBJECT, FALSE); ExitOnFailure(hr, "failed to send progress message"); objectType = SE_UNKNOWN_OBJECT_TYPE; } LExit: ReleaseStr(pwzUser); ReleaseStr(pwzDomain); ReleaseStr(pwzTable); ReleaseStr(pwzObject); ReleaseStr(pwzData); ReleaseStr(pwzAccount); if (pAclNew) { ::LocalFree(pAclNew); } if (psd) { ::LocalFree(psd); } if (psid) { AclFreeSid(psid); } if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/******************************************************************** ConfigureIIsExec - custom action for installing IIs settings - table data will be wrapped and passed in from immediate CA ReadIIsTables ********************************************************************/ extern "C" UINT __stdcall ConfigureIIsExec( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ConfigureIIsExec here"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; BOOL fInitializedCom = FALSE; IMSAdminBase* piMetabase = NULL; SCA_WEB* pswList = NULL; SCA_WEBDIR* pswdList = NULL; SCA_VDIR* psvdList = NULL; SCA_FILTER* psfList = NULL; SCA_APPPOOL *psapList = NULL; SCA_MIMEMAP* psmmList = NULL; SCA_HTTP_HEADER* pshhList = NULL; SCA_PROPERTY *pspList = NULL; SCA_WEBSVCEXT* psWseList = NULL; SCA_WEB_ERROR* psweList = NULL; LPWSTR pwzScriptKey = NULL; LPWSTR pwzCustomActionData = NULL; WCA_WRAPQUERY_HANDLE hUserQuery = NULL; WCA_WRAPQUERY_HANDLE hWebBaseQuery = NULL; WCA_WRAPQUERY_HANDLE hWebDirPropQuery = NULL; WCA_WRAPQUERY_HANDLE hSslCertQuery = NULL; WCA_WRAPQUERY_HANDLE hWebLogQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppExtQuery = NULL; // initialize hr = WcaInitialize(hInstall, "ConfigureIIsExec"); ExitOnFailure(hr, "Failed to initialize"); hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); // Get the CaScript key hr = WcaReadStringFromCaData(&pwzCustomActionData, &pwzScriptKey); ExitOnFailure(hr, "Failed to get CaScript key from custom action data"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to initialize COM"); fInitializedCom = TRUE; // if IIS was uninstalled (thus no IID_IMSAdminBase) allow the // user to still uninstall this package by clicking "Ignore" do { hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void**)&piMetabase); if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "failed to get IID_IMSAdminBase Object"); er = WcaErrorMessage(msierrIISCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction(); // bail with the error result from the CoCreate to kick off a rollback case IDRETRY: hr = S_FALSE; // hit me, baby, one more time break; case IDIGNORE: __fallthrough; default: WcaLog(LOGMSG_STANDARD, "ignoring absent IIS"); // We need to write the empty script to communicate to other deferred CA that there is noting to do. hr = ScaWriteConfigurationScript(pwzScriptKey); ExitOnFailure(hr, "failed to schedule metabase configuration"); ExitFunction1(hr = S_OK); // pretend everything is okay break; } } } while (S_FALSE == hr); // read the msi tables hr = WcaBeginUnwrapQuery(&hUserQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap user query"); hr = ScaWebSvcExtRead(&psWseList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSvcExt, "failed while processing WebServiceExtensions"); hr = ScaAppPoolRead(&psapList, hUserQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadAppPool, "failed while processing WebAppPools"); // MimeMap, Error and HttpHeader need to be read before the virtual directory and web read hr = ScaMimeMapRead(&psmmList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadMimeMap, "failed while processing MimeMaps"); hr = ScaHttpHeaderRead(&pshhList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadHttpHeader, "failed while processing HttpHeaders"); hr = ScaWebErrorRead(&psweList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebError, "failed while processing WebErrors"); hr = WcaBeginUnwrapQuery(&hWebDirPropQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web dir properties query"); hr = WcaBeginUnwrapQuery(&hSslCertQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap ssl certificate query"); hr = WcaBeginUnwrapQuery(&hWebLogQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web log query"); hr = WcaBeginUnwrapQuery(&hWebAppQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application query"); hr = WcaBeginUnwrapQuery(&hWebAppExtQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application extension query"); hr = ScaWebsRead(piMetabase, &psmmList, &pswList, &pshhList, &psweList, hUserQuery, hWebDirPropQuery, hSslCertQuery, hWebLogQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSite, "failed while processing WebSites"); hr = WcaBeginUnwrapQuery(&hWebBaseQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web base query"); hr = ScaWebDirsRead(piMetabase, pswList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData, &pswdList); MessageExitOnFailure(hr, msierrIISFailedReadWebDirs, "failed while processing WebDirs"); hr = ScaVirtualDirsRead(piMetabase, pswList, &psvdList, &psmmList, &pshhList, &psweList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadVDirs, "failed while processing WebVirtualDirs"); hr = ScaFiltersRead(piMetabase, pswList, hWebBaseQuery, &psfList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadFilters, "failed while processing WebFilters"); hr = ScaPropertyRead(&pspList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadProp, "failed while processing WebProperties"); // do uninstall actions (order is important!) hr = ScaPropertyUninstall(piMetabase, pspList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallProp, "failed to uninstall IIS properties"); hr = ScaFiltersUninstall(piMetabase, psfList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallFilters, "failed to schedule uninstall of filters"); hr = ScaVirtualDirsUninstall(piMetabase, psvdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallVDirs, "failed to schedule uninstall of virtual directories"); hr = ScaWebDirsUninstall(piMetabase, pswdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebDirs, "failed to schedule uninstall of web directories"); hr = ScaWebsUninstall(piMetabase, pswList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebs, "failed to schedule uninstall of webs"); hr = ScaAppPoolUninstall(piMetabase, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallAppPool, "failed to schedule uninstall of AppPools"); // do install actions (order is important!) // ScaWebSvcExtCommit contains both uninstall and install actions. hr = ScaWebSvcExtCommit(piMetabase, psWseList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebSvcExt, "failed to schedule install/uninstall of WebSvcExt"); hr = ScaAppPoolInstall(piMetabase, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallAppPool, "failed to schedule install of AppPools"); hr = ScaWebsInstall(piMetabase, pswList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebs, "failed to schedule install of webs"); hr = ScaWebDirsInstall(piMetabase, pswdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebDirs, "failed to schedule install of web directories"); hr = ScaVirtualDirsInstall(piMetabase, psvdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallVDirs, "failed to schedule install of virtual directories"); hr = ScaFiltersInstall(piMetabase, psfList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallFilters, "failed to schedule install of filters"); hr = ScaPropertyInstall(piMetabase, pspList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallProp, "failed to schedule install of properties"); hr = ScaWriteConfigurationScript(pwzScriptKey); ExitOnFailure(hr, "failed to schedule metabase configuration"); LExit: ReleaseStr(pwzScriptKey); ReleaseStr(pwzCustomActionData); WcaFinishUnwrapQuery(hUserQuery); WcaFinishUnwrapQuery(hWebBaseQuery); WcaFinishUnwrapQuery(hWebDirPropQuery); WcaFinishUnwrapQuery(hSslCertQuery); WcaFinishUnwrapQuery(hWebLogQuery); WcaFinishUnwrapQuery(hWebAppQuery); WcaFinishUnwrapQuery(hWebAppExtQuery); if (psWseList) { ScaWebSvcExtFreeList(psWseList); } if (psfList) { ScaFiltersFreeList(psfList); } if (psvdList) { ScaVirtualDirsFreeList(psvdList); } if (pswdList) { ScaWebDirsFreeList(pswdList); } if (pswList) { ScaWebsFreeList(pswList); } if (psmmList) { ScaMimeMapCheckList(psmmList); ScaMimeMapFreeList(psmmList); } if (pshhList) { ScaHttpHeaderCheckList(pshhList); ScaHttpHeaderFreeList(pshhList); } if (psweList) { ScaWebErrorCheckList(psweList); ScaWebErrorFreeList(psweList); } ReleaseObject(piMetabase); if (fInitializedCom) { ::CoUninitialize(); } er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
extern "C" UINT __stdcall ExecSecureObjectsRollback( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug ExecSecureObjectsRollback"); HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; LPWSTR pwz = NULL; LPWSTR pwzData = NULL; LPWSTR pwzObject = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzSecurityInfo = NULL; SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE; PSECURITY_DESCRIPTOR psd = NULL; ULONG psdSize; SECURITY_DESCRIPTOR_CONTROL sdc = {0}; SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; PACL pDacl = NULL; BOOL bDaclPresent = false; BOOL bDaclDefaulted = false; DWORD dwRevision = 0; int iProtected; // initialize hr = WcaInitialize(hInstall, "ExecSecureObjectsRollback"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty(L"CustomActionData", &pwzData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); pwz = pwzData; hr = WcaReadStringFromCaData(&pwz, &pwzObject); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzTable); ExitOnFailure(hr, "failed to process CustomActionData"); objectType = SEObjectTypeFromString(const_cast<LPCWSTR> (pwzTable)); if (SE_UNKNOWN_OBJECT_TYPE != objectType) { hr = WcaReadStringFromCaData(&pwz, &pwzSecurityInfo); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, &iProtected); ExitOnFailure(hr, "failed to process CustomActionData"); if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(pwzSecurityInfo,SDDL_REVISION_1,&psd,&psdSize)) { ExitOnLastError(hr, "failed to convert security descriptor string to a valid security descriptor"); } if (!::GetSecurityDescriptorDacl(psd,&bDaclPresent,&pDacl,&bDaclDefaulted)) { hr = E_UNEXPECTED; ExitOnFailure2(hr, "failed to get security descriptor's DACL - error code: %d",pwzSecurityInfo,GetLastError()); } // The below situation may always be caught by the above if block - the documentation isn't very clear. To be safe, we're going to test for it. if (!bDaclPresent) { hr = E_UNEXPECTED; ExitOnFailure(hr, "security descriptor does not contain a DACL"); } //Need to see if DACL is protected so getting Descriptor information if (!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision)) { ExitOnLastError1(hr, "failed to get security descriptor control for object: %ls", pwzObject); } // Write a 1 if DACL is protected, 0 otherwise switch (iProtected) { case 0: // Unnecessary to do anything - leave si to the default flags break; case 1: si = si | PROTECTED_DACL_SECURITY_INFORMATION; break; default: hr = E_UNEXPECTED; ExitOnFailure(hr, "unrecognized value in CustomActionData"); break; } er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, pDacl, NULL); ExitOnFailure2(hr = HRESULT_FROM_WIN32(er), "failed to set security info for object: %ls error code: %d", pwzObject, GetLastError()); } else { MessageExitOnFailure1(hr = E_UNEXPECTED, msierrSecureObjectsUnknownType, "unknown object type: %ls", pwzTable); } LExit: ReleaseStr(pwzData); ReleaseStr(pwzObject); ReleaseStr(pwzTable); ReleaseStr(pwzSecurityInfo); if (psd) { ::LocalFree(psd); } if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/******************************************************************** ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings ********************************************************************/ extern "C" UINT __stdcall ConfigureIIs7Exec( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ConfigureIIs7Exec here"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzScriptKey = NULL; LPWSTR pwzCustomActionData = NULL; SCA_WEB7* pswList = NULL; SCA_WEBDIR7* pswdList = NULL; SCA_VDIR7* psvdList = NULL; SCA_FILTER* psfList = NULL; SCA_APPPOOL *psapList = NULL; SCA_MIMEMAP* psmmList = NULL; SCA_HTTP_HEADER* pshhList = NULL; SCA_PROPERTY *pspList = NULL; SCA_WEBSVCEXT* psWseList = NULL; SCA_WEB_ERROR* psweList = NULL; WCA_WRAPQUERY_HANDLE hUserQuery = NULL; WCA_WRAPQUERY_HANDLE hWebBaseQuery = NULL; WCA_WRAPQUERY_HANDLE hWebDirPropQuery = NULL; WCA_WRAPQUERY_HANDLE hSslCertQuery = NULL; WCA_WRAPQUERY_HANDLE hWebLogQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppQuery = NULL; WCA_WRAPQUERY_HANDLE hWebAppExtQuery = NULL; // initialize hr = WcaInitialize(hInstall, "ConfigureIIs7Exec"); ExitOnFailure(hr, "Failed to initialize"); hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); // Get the CaScript key hr = WcaReadStringFromCaData(&pwzCustomActionData, &pwzScriptKey); ExitOnFailure(hr, "Failed to get CaScript key from custom action data"); // read the msi tables hr = WcaBeginUnwrapQuery(&hUserQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap user query"); hr = ScaWebSvcExtRead(&psWseList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSvcExt, "failed while processing WebServiceExtensions"); hr = ScaAppPoolRead(&psapList, hUserQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadAppPool, "failed while processing WebAppPools"); // MimeMap, Error and HttpHeader need to be read before the virtual directory and web read hr = ScaMimeMapRead(&psmmList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadMimeMap, "failed while processing MimeMaps"); hr = ScaHttpHeaderRead(&pshhList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadHttpHeader, "failed while processing HttpHeaders"); hr = ScaWebErrorRead(&psweList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebError, "failed while processing WebErrors"); hr = WcaBeginUnwrapQuery(&hWebDirPropQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web dir properties query"); hr = WcaBeginUnwrapQuery(&hSslCertQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap ssl certificate query"); hr = WcaBeginUnwrapQuery(&hWebLogQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web log query"); hr = WcaBeginUnwrapQuery(&hWebAppQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application query"); hr = WcaBeginUnwrapQuery(&hWebAppExtQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web application extension query"); hr = ScaWebsRead7(&pswList, &pshhList, &psweList, hUserQuery, hWebDirPropQuery, hSslCertQuery, hWebLogQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadWebSite, "failed while processing WebSites"); hr = WcaBeginUnwrapQuery(&hWebBaseQuery, &pwzCustomActionData); ExitOnFailure(hr, "Failed to unwrap web base query"); hr = ScaWebDirsRead7(pswList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData, &pswdList); MessageExitOnFailure(hr, msierrIISFailedReadWebDirs, "failed while processing WebDirs"); hr = ScaVirtualDirsRead7(pswList, &psvdList, &psmmList, &pshhList, &psweList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadVDirs, "failed while processing WebVirtualDirs"); hr = ScaFiltersRead7(pswList, hWebBaseQuery, &psfList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadFilters, "failed while processing WebFilters"); hr = ScaPropertyRead(&pspList, &pwzCustomActionData); MessageExitOnFailure(hr, msierrIISFailedReadProp, "failed while processing WebProperties"); // do uninstall actions (order is important!) hr = ScaPropertyUninstall7(pspList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallProp, "failed to uninstall IIS properties"); hr = ScaFiltersUninstall7(psfList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallFilters, "failed to schedule uninstall of filters"); hr = ScaVirtualDirsUninstall7(psvdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallVDirs, "failed to schedule uninstall of virtual directories"); hr = ScaWebDirsUninstall7(pswdList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebDirs, "failed to schedule uninstall of web directories"); hr = ScaWebsUninstall7(pswList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebs, "failed to schedule uninstall of webs"); hr = ScaAppPoolUninstall7(psapList); MessageExitOnFailure(hr, msierrIISFailedSchedUninstallAppPool, "failed to schedule uninstall of AppPools"); // do install actions (order is important!) // ScaWebSvcExtCommit contains both uninstall and install actions. hr = ScaWebSvcExtCommit7(psWseList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebSvcExt, "failed to schedule install/uninstall of WebSvcExt"); hr = ScaAppPoolInstall7(psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallAppPool, "failed to schedule install of AppPools"); hr = ScaWebsInstall7(pswList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebs, "failed to schedule install of webs"); hr = ScaWebDirsInstall7(pswdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebDirs, "failed to schedule install of web directories"); hr = ScaVirtualDirsInstall7(psvdList, psapList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallVDirs, "failed to schedule install of virtual directories"); hr = ScaFiltersInstall7(psfList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallFilters, "failed to schedule install of filters"); hr = ScaPropertyInstall7(pspList); MessageExitOnFailure(hr, msierrIISFailedSchedInstallProp, "failed to schedule install of properties"); hr = ScaWriteConfigurationScript(pwzScriptKey); ExitOnFailure(hr, "failed to schedule metabase configuration"); LExit: ReleaseNullStr(pwzScriptKey); ReleaseNullStr(pwzCustomActionData); WcaFinishUnwrapQuery(hUserQuery); WcaFinishUnwrapQuery(hWebBaseQuery); WcaFinishUnwrapQuery(hWebDirPropQuery); WcaFinishUnwrapQuery(hSslCertQuery); WcaFinishUnwrapQuery(hWebLogQuery); WcaFinishUnwrapQuery(hWebAppQuery); WcaFinishUnwrapQuery(hWebAppExtQuery); if (psWseList) { ScaWebSvcExtFreeList(psWseList); } if (psfList) { ScaFiltersFreeList(psfList); } if (psvdList) { ScaVirtualDirsFreeList7(psvdList); } if (pswdList) { ScaWebDirsFreeList7(pswdList); } if (pswList) { ScaWebsFreeList7(pswList); } if (psmmList) { ScaMimeMapFreeList(psmmList); } if (pshhList) { ScaHttpHeaderCheckList(pshhList); ScaHttpHeaderFreeList(pshhList); } if (psweList) { ScaWebErrorCheckList(psweList); ScaWebErrorFreeList(psweList); } er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** CaExecServiceConfig - entry point for ServiceConfig Custom Action. NOTE: deferred CustomAction since it modifies the machine NOTE: CustomActionData == wzServiceName\tfNewService\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\tfNewService\t... *******************************************************************/ extern "C" UINT __stdcall ExecServiceConfig( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ExecServiceConfig"); HRESULT hr = S_OK; DWORD er = 0; LPWSTR pwzCustomActionData = NULL; LPWSTR pwz = NULL; LPWSTR pwzScriptKey = NULL; WCA_CASCRIPT_HANDLE hRollbackScript = NULL; LPWSTR pwzServiceName = NULL; BOOL fNewService = FALSE; LPWSTR pwzFirstFailureActionType = NULL; LPWSTR pwzSecondFailureActionType = NULL; LPWSTR pwzThirdFailureActionType = NULL; LPWSTR pwzProgramCommandLine = NULL; LPWSTR pwzRebootMessage = NULL; DWORD dwResetPeriodInDays = 0; DWORD dwRestartServiceDelayInSeconds = 0; LPVOID lpMsgBuf = NULL; SC_HANDLE hSCM = NULL; SC_HANDLE hService = NULL; DWORD dwRestartDelay = 0; WCHAR wzActionName[32] = { 0 }; DWORD cbExistingServiceConfig = 0; SERVICE_FAILURE_ACTIONSW* psfa = NULL; // initialize hr = WcaInitialize(hInstall, "ExecServiceConfig"); ExitOnFailure(hr, "failed to initialize"); // Open the Services Control Manager up front. hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (NULL == hSCM) { er = ::GetLastError(); hr = HRESULT_FROM_WIN32(er); #pragma prefast(push) #pragma prefast(disable:25028) ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, er, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); #pragma prefast(pop) ExitOnFailure1(hr, "Failed to get handle to SCM. Error: %ls", (LPWSTR)lpMsgBuf); } // First, get the script key out of the CustomActionData and // use that to create the rollback script for this action. hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); if (!pwzScriptKey) { hr = E_UNEXPECTED; ExitOnFailure(hr, "Failed due to unexpected CustomActionData passed."); } ExitOnFailure(hr, "Failed to read encoding key from CustomActionData."); hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); ExitOnFailure(hr, "Failed to open rollback CustomAction script."); // Next, loop through the rest of the CustomActionData, processing // each service config row in turn. while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&fNewService)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwResetPeriodInDays)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwRestartServiceDelayInSeconds)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); ExitOnFailure(hr, "failed to process CustomActionData"); WcaLog(LOGMSG_VERBOSE, "Configuring Service: %ls", pwzServiceName); // Open the handle with all the permissions we might need: // SERVICE_QUERY_CONFIG is needed for QueryServiceConfig2(). // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2(). // SERVICE_START is required in order to handle SC_ACTION_RESTART action. hr = GetService(hSCM, pwzServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_START, &hService); ExitOnFailure1(hr, "Failed to get service: %ls", pwzServiceName); // If we are configuring a service that existed on the machine, we need to // read the existing service configuration and write it out to the rollback // log so rollback can put it back if anything goes wrong. if (!fNewService) { // First, read the existing service config. if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &cbExistingServiceConfig) && ERROR_INSUFFICIENT_BUFFER != ::GetLastError()) { ExitWithLastError(hr, "Failed to get current service config info."); } psfa = static_cast<LPSERVICE_FAILURE_ACTIONSW>(MemAlloc(cbExistingServiceConfig, TRUE)); ExitOnNull(psfa, hr, E_OUTOFMEMORY, "failed to allocate memory for service failure actions."); if (!::QueryServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)psfa, cbExistingServiceConfig, &cbExistingServiceConfig)) { ExitOnLastError(hr, "failed to Query Service."); } // Build up rollback log so we can restore service state if necessary hr = WcaCaScriptWriteString(hRollbackScript, pwzServiceName); ExitOnFailure(hr, "Failed to add service name to Rollback Log"); // If this service struct is empty, fill in default values if (3 > psfa->cActions) { hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); hr = WcaCaScriptWriteString(hRollbackScript, c_wzActionTypeNone); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); } else { // psfa actually had actions defined, so use the first three. for (int i = 0; i < 3; ++i) { hr = GetSCActionTypeString(psfa->lpsaActions[i].Type, wzActionName, countof(wzActionName)); ExitOnFailure(hr, "failed to query SFA object"); if (SC_ACTION_RESTART == psfa->lpsaActions[i].Type) { dwRestartDelay = psfa->lpsaActions[i].Delay / 1000; } hr = WcaCaScriptWriteString(hRollbackScript, wzActionName); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); } } hr = WcaCaScriptWriteNumber(hRollbackScript, psfa->dwResetPeriod / (24 * 60 * 60)); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaCaScriptWriteNumber(hRollbackScript, dwRestartDelay); ExitOnFailure(hr, "failed to add data to CustomActionData"); // Handle the null cases. if (!psfa->lpCommand) { psfa->lpCommand = L""; } hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpCommand); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); // Handle the null cases. if (!psfa->lpRebootMsg) { psfa->lpRebootMsg = L""; } hr = WcaCaScriptWriteString(hRollbackScript, psfa->lpRebootMsg); ExitOnFailure(hr, "failed to add data to Rollback CustomActionData"); // Nudge the system to get all our rollback data written to disk. WcaCaScriptFlush(hRollbackScript); ReleaseNullMem(psfa); } hr = ConfigureService(hSCM, hService, pwzServiceName, dwRestartServiceDelayInSeconds, pwzFirstFailureActionType, pwzSecondFailureActionType, pwzThirdFailureActionType, dwResetPeriodInDays, pwzRebootMessage, pwzProgramCommandLine); ExitOnFailure1(hr, "Failed to configure service: %ls", pwzServiceName); hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); ExitOnFailure(hr, "failed to send progress message"); // Per-service cleanup ::CloseServiceHandle(hService); hService = NULL; dwResetPeriodInDays = 0; dwRestartServiceDelayInSeconds = 0; } LExit: WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); if (lpMsgBuf) { ::LocalFree(lpMsgBuf); } if (hService) { ::CloseServiceHandle(hService); } if (hSCM) { ::CloseServiceHandle(hSCM); } ReleaseMem(psfa); ReleaseStr(pwzRebootMessage); ReleaseStr(pwzProgramCommandLine); ReleaseStr(pwzThirdFailureActionType); ReleaseStr(pwzSecondFailureActionType); ReleaseStr(pwzFirstFailureActionType); ReleaseStr(pwzServiceName); ReleaseStr(pwzScriptKey); ReleaseStr(pwzCustomActionData); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
UINT __stdcall ZTokenReplace(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; hr = WcaInitialize(hInstall, "ZTokenReplace"); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); UINT rc; char file[2048]; char prop[1024]; DWORD filesize = sizeof(file); DWORD propsize = sizeof(prop); rc = MsiGetProperty(hInstall, "File", &file[0], &filesize); if (rc != ERROR_SUCCESS) { WcaLog(LOGMSG_STANDARD, "Unable to get property: File"); return WcaFinalize(ERROR_INSTALL_FAILURE); } rc = MsiGetProperty(hInstall, "NumberOfTokens", &prop[0], &propsize); if (rc != ERROR_SUCCESS) { WcaLog(LOGMSG_STANDARD, "Unable to get property: NumberOfTokens"); return WcaFinalize(ERROR_INSTALL_FAILURE); } int num = atoi(prop); if (num > 0) { char **tokens = new char *[num]; char **values = new char *[num]; for (int i = 0; i < num; ++i) { char key[32]; propsize = sizeof(prop); sprintf(key, "Token%u", i + 1); MsiGetProperty(hInstall, key, &prop[0], &propsize); tokens[i] = strdup(prop); propsize = sizeof(prop); sprintf(key, "Value%u", i + 1); MsiGetProperty(hInstall, key, &prop[0], &propsize); values[i] = strdup(prop); if (values[i][propsize - 1] == '\\') values[i][propsize - 1] = '\0'; } int ret = FindAndReplace(file, num, tokens, values); for (int i = 0; i < num; ++i) { free(tokens[i]); free(values[i]); } if (ret) return WcaFinalize(ERROR_INSTALL_FAILURE); } LExit: er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** SchedServiceConfig - entry point for SchedServiceConfig 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 er = ERROR_SUCCESS; LPWSTR pwzScriptKey = NULL; LPWSTR pwzCustomActionData = NULL; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; LPWSTR pwzData = NULL; int iData = 0; DWORD cServices = 0; // initialize hr = WcaInitialize(hInstall, "SchedServiceConfig"); ExitOnFailure(hr, "Failed to initialize."); // Get the script key for this CustomAction and put it on the front of the // CustomActionData of the install action. hr = WcaCaScriptCreateKey(&pwzScriptKey); ExitOnFailure(hr, "Failed to get encoding key."); hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add encoding key to CustomActionData."); // 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))) { INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; // Get component name to check if we are installing it. If so // then add the table data to the CustomActionData, otherwise // skip it. hr = WcaGetRecordString(hRec, QSC_COMPONENT, &pwzData); ExitOnFailure(hr, "Failed to get component name"); hr = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); ExitOnFailure1(hr = HRESULT_FROM_WIN32(hr), "Failed to get install state for Component: %ls", pwzData); if (WcaIsInstalling(isInstalled, isAction)) { // 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 name to CustomActionData."); hr = WcaGetRecordInteger(hRec, QSC_NEWSERVICE, &iData); ExitOnFailure(hr, "Failed to get ServiceConfig.NewService."); hr = WcaWriteIntegerToCaData(0 != iData, &pwzCustomActionData); ExitOnFailure(hr, "Failed to add NewService 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 (S_FALSE == hr) // 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 (S_FALSE == hr) // 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 = WcaGetRecordFormattedString(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; } } // 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 (0 < cServices) { hr = WcaDoDeferredAction(L"RollbackServiceConfig", pwzScriptKey, cServices * COST_SERVICECONFIG); ExitOnFailure(hr, "failed to schedule RollbackServiceConfig action"); hr = WcaDoDeferredAction(L"ExecServiceConfig", pwzCustomActionData, cServices * COST_SERVICECONFIG); ExitOnFailure(hr, "failed to schedule ExecServiceConfig action"); } LExit: ReleaseStr(pwzData); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzScriptKey); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** SchedNetFx - entry point for NetFx Custom Action ********************************************************************/ extern "C" UINT __stdcall SchedNetFx( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedNetFx"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzInstallCustomActionData = NULL; LPWSTR pwzUninstallCustomActionData = NULL; UINT uiCost = 0; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; PMSIHANDLE hViewGac = NULL; PMSIHANDLE hRecGac = NULL; LPWSTR pwzId = NULL; LPWSTR pwzData = NULL; LPWSTR pwzTemp = NULL; LPWSTR pwzFile = NULL; int iPriority = 0; int iAssemblyCost = 0; int iAttributes = 0; LPWSTR pwzFileApp = NULL; LPWSTR pwzDirAppBase = NULL; LPWSTR pwzComponent = NULL; INSTALLSTATE isInstalled; INSTALLSTATE isAction; LPWSTR pwz32Ngen = NULL; LPWSTR pwz64Ngen = NULL; BOOL f32NgenExeExists = FALSE; BOOL f64NgenExeExists = FALSE; BOOL fNeedInstallUpdate32 = FALSE; BOOL fNeedUninstallUpdate32 = FALSE; BOOL fNeedInstallUpdate64 = FALSE; BOOL fNeedUninstallUpdate64 = FALSE; // initialize hr = WcaInitialize(hInstall, "SchedNetFx"); ExitOnFailure(hr, "failed to initialize"); hr = GetNgenPath(&pwz32Ngen, FALSE); f32NgenExeExists = SUCCEEDED(hr); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) { hr = ERROR_SUCCESS; WcaLog(LOGMSG_STANDARD, "Failed to find 32bit ngen. No actions will be scheduled to create native images for 32bit."); } ExitOnFailure(hr, "failed to get 32bit ngen.exe path"); hr = GetNgenPath(&pwz64Ngen, TRUE); f64NgenExeExists = SUCCEEDED(hr); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) { hr = ERROR_SUCCESS; WcaLog(LOGMSG_STANDARD, "Failed to find 64bit ngen. No actions will be scheduled to create native images for 64bit."); } ExitOnFailure(hr, "failed to get 64bit ngen.exe path"); // loop through all the NetFx records hr = WcaOpenExecuteView(vcsNgenQuery, &hView); ExitOnFailure(hr, "failed to open view on NetFxNativeImage table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // Get Id hr = WcaGetRecordString(hRec, ngqId, &pwzId); ExitOnFailure(hr, "failed to get NetFxNativeImage.NetFxNativeImage"); // Get File hr = WcaGetRecordString(hRec, ngqFile, &pwzData); ExitOnFailure1(hr, "failed to get NetFxNativeImage.File_ for record: %ls", pwzId); hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedFile, pwzData); ExitOnFailure1(hr, "failed to format file string for file: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzFile); ExitOnFailure1(hr, "failed to get formatted string for file: %ls", pwzData); // Get Priority hr = WcaGetRecordInteger(hRec, ngqPriority, &iPriority); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Priority for record: %ls", pwzId); if (0 == iPriority) iAssemblyCost = COST_NGEN_BLOCKING; else iAssemblyCost = COST_NGEN_NONBLOCKING; // Get Attributes hr = WcaGetRecordInteger(hRec, ngqAttributes, &iAttributes); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Attributes for record: %ls", pwzId); // Get File_Application or leave pwzFileApp NULL. hr = WcaGetRecordFormattedString(hRec, ngqFileApp, &pwzData); ExitOnFailure1(hr, "failed to get NetFxNativeImage.File_Application for record: %ls", pwzId); // Check if the value resolves to a valid file ID. if (S_OK == FileIdExists(pwzData)) { // Resolve the file ID to a path. hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedFile, pwzData); ExitOnFailure1(hr, "failed to format file application string for file: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzFileApp); ExitOnFailure1(hr, "failed to get formatted string for file application: %ls", pwzData); } else { // Assume record formatted to a path already. hr = StrAllocString(&pwzFileApp, pwzData, 0); ExitOnFailure1(hr, "failed to allocate string for file path: %ls", pwzData); hr = PathEnsureQuoted(&pwzFileApp, FALSE); ExitOnFailure1(hr, "failed to quote file path: %ls", pwzData); } // Get Directory_ApplicationBase or leave pwzDirAppBase NULL. hr = WcaGetRecordFormattedString(hRec, ngqDirAppBase, &pwzData); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Directory_ApplicationBase for record: %ls", pwzId); if (WcaIsUnicodePropertySet(pwzData)) { // Resolve the directory ID to a path. hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedDirectory, pwzData); ExitOnFailure1(hr, "failed to format directory application base string for property: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzDirAppBase); ExitOnFailure1(hr, "failed to get formatted string for directory application base: %ls", pwzData); } else { // Assume record formatted to a path already. hr = StrAllocString(&pwzDirAppBase, pwzData, 0); ExitOnFailure1(hr, "failed to allocate string for directory path: %ls", pwzData); hr = PathEnsureQuoted(&pwzDirAppBase, TRUE); ExitOnFailure1(hr, "failed to quote and backslashify directory: %ls", pwzData); } // Get Component hr = WcaGetRecordString(hRec, ngqComponent, &pwzComponent); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Directory_ApplicationBase for record: %ls", pwzId); er = ::MsiGetComponentStateW(hInstall, pwzComponent, &isInstalled, &isAction); ExitOnWin32Error1(er, hr, "failed to get install state for Component: %ls", pwzComponent); // // Figure out if it's going to be GAC'd. The possibility exists that no assemblies are going to be GAC'd // so we have to check for the MsiAssembly table first. // if (S_OK == WcaTableExists(L"MsiAssembly")) { hr = WcaOpenView(vcsNgenGac, &hViewGac); ExitOnFailure(hr, "failed to open view on File/MsiAssembly table"); hr = WcaExecuteView(hViewGac, hRec); ExitOnFailure(hr, "failed to execute view on File/MsiAssembly table"); hr = WcaFetchSingleRecord(hViewGac, &hRecGac); ExitOnFailure(hr, "failed to fetch File_Assembly from File/MsiAssembly table"); if (S_FALSE != hr) { hr = WcaGetRecordString(hRecGac, nggApplication, &pwzData); ExitOnFailure(hr, "failed to get MsiAssembly.File_Application"); // If it's in the GAC replace the file name with the strong name if (L'\0' == pwzData[0]) { hr = GetStrongName(&pwzFile, pwzComponent); ExitOnFailure1(hr, "failed to get strong name for component: %ls", pwzData); } } } // // Schedule the work // if (!(iAttributes & NGEN_32BIT) && !(iAttributes & NGEN_64BIT)) ExitOnFailure1(hr = E_INVALIDARG, "Neither 32bit nor 64bit is specified for NGEN of file: %ls", pwzFile); if (WcaIsInstalling(isInstalled, isAction) || WcaIsReInstalling(isInstalled, isAction)) { if (iAttributes & NGEN_32BIT && f32NgenExeExists) { // Assemble the install command line hr = CreateInstallCommand(&pwzData, pwz32Ngen, pwzFile, iPriority, iAttributes, pwzFileApp, pwzDirAppBase); ExitOnFailure(hr, "failed to create install command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(iAssemblyCost, &pwzInstallCustomActionData); ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += iAssemblyCost; fNeedInstallUpdate32 = TRUE; } if (iAttributes & NGEN_64BIT && f64NgenExeExists) { // Assemble the install command line hr = CreateInstallCommand(&pwzData, pwz64Ngen, pwzFile, iPriority, iAttributes, pwzFileApp, pwzDirAppBase); ExitOnFailure(hr, "failed to create install command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(iAssemblyCost, &pwzInstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += iAssemblyCost; fNeedInstallUpdate64 = TRUE; } } else if (WcaIsUninstalling(isInstalled, isAction)) { if (iAttributes & NGEN_32BIT && f32NgenExeExists) { hr = StrAllocFormatted(&pwzData, L"%s uninstall %s", pwz32Ngen, pwzFile); ExitOnFailure(hr, "failed to create update 32 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; fNeedUninstallUpdate32 = TRUE; } if (iAttributes & NGEN_64BIT && f64NgenExeExists) { hr = StrAllocFormatted(&pwzData, L"%s uninstall %s", pwz64Ngen, pwzFile); ExitOnFailure(hr, "failed to create update 64 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; fNeedUninstallUpdate64 = TRUE; } } } if (E_NOMOREITEMS == hr) hr = S_OK; ExitOnFailure(hr, "failed while looping through all files to create native images for"); // If we need 32 bit install update if (fNeedInstallUpdate32) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz32Ngen); ExitOnFailure(hr, "failed to create install update 32 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to install custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzInstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to install custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // If we need 32 bit uninstall update if (fNeedUninstallUpdate32) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz32Ngen); ExitOnFailure(hr, "failed to create uninstall update 32 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to uninstall custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to uninstall custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // If we need 64 bit install update if (fNeedInstallUpdate64) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz64Ngen); ExitOnFailure(hr, "failed to create install update 64 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to install custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzInstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to install custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // If we need 64 bit install update if (fNeedUninstallUpdate64) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz64Ngen); ExitOnFailure(hr, "failed to create uninstall update 64 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to uninstall custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to uninstall custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // Add to progress bar if ((pwzInstallCustomActionData && *pwzInstallCustomActionData) || (pwzUninstallCustomActionData && *pwzUninstallCustomActionData)) { hr = WcaProgressMessage(uiCost, TRUE); ExitOnFailure(hr, "failed to extend progress bar for NetFxExecuteNativeImage"); } // Schedule the install custom action if (pwzInstallCustomActionData && *pwzInstallCustomActionData) { hr = WcaSetProperty(L"NetFxExecuteNativeImageInstall", pwzInstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageInstall action"); hr = WcaSetProperty(L"NetFxExecuteNativeImageCommitInstall", pwzInstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageCommitInstall action"); } // Schedule the uninstall custom action if (pwzUninstallCustomActionData && *pwzUninstallCustomActionData) { hr = WcaSetProperty(L"NetFxExecuteNativeImageUninstall", pwzUninstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageUninstall action"); hr = WcaSetProperty(L"NetFxExecuteNativeImageCommitUninstall", pwzUninstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageCommitUninstall action"); } LExit: ReleaseStr(pwzInstallCustomActionData); ReleaseStr(pwzUninstallCustomActionData); ReleaseStr(pwzId); ReleaseStr(pwzData); ReleaseStr(pwzTemp); ReleaseStr(pwzFile); ReleaseStr(pwzFileApp); ReleaseStr(pwzDirAppBase); ReleaseStr(pwzComponent); ReleaseStr(pwz32Ngen); ReleaseStr(pwz64Ngen); if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/* Checks SERVICENAME, PORT and BUFFERSIZE parameters */ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall) { wchar_t ServiceName[MAX_PATH]={0}; wchar_t SkipNetworking[MAX_PATH]={0}; wchar_t QuickConfig[MAX_PATH]={0}; wchar_t Password[MAX_PATH]={0}; wchar_t EscapedPassword[2*MAX_PATH+2]; wchar_t Port[6]; wchar_t BufferPoolSize[16]; DWORD PortLen=6; bool haveInvalidPort=false; const wchar_t *ErrorMsg=0; HRESULT hr= S_OK; UINT er= ERROR_SUCCESS; hr = WcaInitialize(hInstall, __FUNCTION__); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); DWORD ServiceNameLen = MAX_PATH; MsiGetPropertyW (hInstall, L"SERVICENAME", ServiceName, &ServiceNameLen); if(ServiceName[0]) { if(ServiceNameLen > 256) { ErrorMsg= L"Invalid service name. The maximum length is 256 characters."; goto LExit; } for(DWORD i=0; i< ServiceNameLen;i++) { if(ServiceName[i] == L'\\' || ServiceName[i] == L'/' || ServiceName[i]=='\'' || ServiceName[i] ==L'"') { ErrorMsg = L"Invalid service name. Forward slash and back slash are forbidden." L"Single and double quotes are also not permitted."; goto LExit; } } if(CheckServiceExists(ServiceName)) { ErrorMsg= L"A service with the same name already exists. " L"Please use a different name."; goto LExit; } } DWORD PasswordLen= MAX_PATH; MsiGetPropertyW (hInstall, L"PASSWORD", Password, &PasswordLen); EscapeCommandLine(Password, EscapedPassword, sizeof(EscapedPassword)/sizeof(EscapedPassword[0])); MsiSetPropertyW(hInstall,L"ESCAPEDPASSWORD",EscapedPassword); DWORD SkipNetworkingLen= MAX_PATH; MsiGetPropertyW(hInstall, L"SKIPNETWORKING", SkipNetworking, &SkipNetworkingLen); MsiGetPropertyW(hInstall, L"PORT", Port, &PortLen); if(SkipNetworking[0]==0 && Port[0] != 0) { /* Strip spaces */ for(DWORD i=PortLen-1; i > 0; i--) { if(Port[i]== ' ') Port[i] = 0; } if(PortLen > 5 || PortLen <= 3) haveInvalidPort = true; else { for (DWORD i=0; i< PortLen && Port[i] != 0;i++) { if(Port[i] < '0' || Port[i] >'9') { haveInvalidPort=true; break; } } } if (haveInvalidPort) { ErrorMsg = L"Invalid port number. Please use a number between 1025 and 65535."; goto LExit; } short port = (short)_wtoi(Port); if (!IsPortFree(port)) { ErrorMsg = L"The TCP Port you selected is already in use. " L"Please choose a different port."; goto LExit; } } DWORD QuickConfigLen = MAX_PATH; MsiGetPropertyW (hInstall, L"STDCONFIG", QuickConfig, &QuickConfigLen); if(QuickConfig[0] !=0) { MEMORYSTATUSEX memstatus; memstatus.dwLength =sizeof(memstatus); wchar_t invalidValueMsg[256]; if (!GlobalMemoryStatusEx(&memstatus)) { WcaLog(LOGMSG_STANDARD, "Error %u from GlobalMemoryStatusEx", GetLastError()); er= ERROR_INSTALL_FAILURE; goto LExit; } DWORD BufferPoolSizeLen= 16; MsiGetPropertyW(hInstall, L"BUFFERPOOLSIZE", BufferPoolSize, &BufferPoolSizeLen); /* Strip spaces */ for(DWORD i=BufferPoolSizeLen-1; i > 0; i--) { if(BufferPoolSize[i]== ' ') BufferPoolSize[i] = 0; } unsigned long long availableMemory= GetMaxBufferSize(memstatus.ullTotalPhys)/ONE_MB; swprintf_s(invalidValueMsg, L"Invalid buffer pool size. Please use a number between 1 and %llu", availableMemory); if(BufferPoolSizeLen == 0 || BufferPoolSizeLen > 15) { ErrorMsg= invalidValueMsg; goto LExit; } for (DWORD i=0; i < BufferPoolSizeLen && BufferPoolSize[BufferPoolSizeLen]; i++) { if(BufferPoolSize[i]< '0' || BufferPoolSize[i] > '9') { ErrorMsg= invalidValueMsg; goto LExit; } } BufferPoolSize[BufferPoolSizeLen]=0; MsiSetPropertyW(hInstall, L"BUFFERPOOLSIZE", BufferPoolSize); long long sz = _wtoi64(BufferPoolSize); if(sz <= 0 || sz > (long long)availableMemory) { if(sz > 0) { swprintf_s(invalidValueMsg, L"Value for buffer pool size is too large." L"Only approximately %llu MB is available for allocation." L"Please use a number between 1 and %llu.", availableMemory, availableMemory); } ErrorMsg= invalidValueMsg; goto LExit; } } LExit: MsiSetPropertyW (hInstall, L"WarningText", ErrorMsg); return WcaFinalize(er); }
/******************************************************************** MessageQueuingInstall - CUSTOM ACTION ENTRY POINT for installing MSMQ message queues ********************************************************************/ extern "C" UINT __stdcall MessageQueuingInstall(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; MQI_MESSAGE_QUEUE_LIST lstMessageQueues; MQI_MESSAGE_QUEUE_PERMISSION_LIST lstMessageQueuePermissions; int iCost = 0; LPWSTR pwzRollbackActionData = NULL; LPWSTR pwzExecuteActionData = NULL; ::ZeroMemory(&lstMessageQueues, sizeof(lstMessageQueues)); ::ZeroMemory(&lstMessageQueuePermissions, sizeof(lstMessageQueuePermissions)); // initialize hr = WcaInitialize(hInstall, "MessageQueuingInstall"); ExitOnFailure(hr, "Failed to initialize"); do { hr = MqiInitialize(); if (S_FALSE == hr) { WcaLog(LOGMSG_STANDARD, "Failed to load mqrt.dll."); er = WcaErrorMessage(msierrMsmqCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitFunction1(hr = E_FAIL); // bail with error case IDRETRY: break; // retry case IDIGNORE: __fallthrough; default: ExitFunction1(hr = S_OK); // pretend everything is okay and bail } } ExitOnFailure(hr, "Failed to initialize MSMQ."); } while (S_FALSE == hr); // read message queues hr = MqiMessageQueueRead(&lstMessageQueues); ExitOnFailure(hr, "Failed to read MessageQueue table"); // read message queue permissions hr = MqiMessageQueuePermissionRead(&lstMessageQueues, &lstMessageQueuePermissions); ExitOnFailure(hr, "Failed to read message queue permissions"); // verify message queue elementes hr = MqiMessageQueueVerify(&lstMessageQueues); ExitOnFailure(hr, "Failed to verify message queue elements."); if (lstMessageQueues.iInstallCount || lstMessageQueuePermissions.iInstallCount) { // schedule rollback action hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzRollbackActionData); ExitOnFailure(hr, "Failed to add message queue permissions to rollback action data"); hr = MqiMessageQueueInstall(&lstMessageQueues, TRUE, &pwzRollbackActionData); ExitOnFailure(hr, "Failed to add message queues to rollback action data"); hr = WcaDoDeferredAction(L"MessageQueuingRollbackInstall", pwzRollbackActionData, 0); ExitOnFailure(hr, "Failed to schedule MessageQueuingRollbackInstall"); // schedule execute action hr = MqiMessageQueueInstall(&lstMessageQueues, FALSE, &pwzExecuteActionData); ExitOnFailure(hr, "Failed to add message queues to execute action data"); iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_CREATE; hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzExecuteActionData); ExitOnFailure(hr, "Failed to add message queue permissions to execute action data"); iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_PERMISSION_ADD; hr = WcaDoDeferredAction(L"MessageQueuingExecuteInstall", pwzExecuteActionData, iCost); ExitOnFailure(hr, "Failed to schedule MessageQueuingExecuteInstall"); } hr = S_OK; LExit: // clean up MqiMessageQueueFreeList(&lstMessageQueues); MqiMessageQueuePermissionFreeList(&lstMessageQueuePermissions); ReleaseStr(pwzRollbackActionData); ReleaseStr(pwzExecuteActionData); // uninitialize MqiUninitialize(); er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/****************************************************************** SchedXmlConfig - entry point for XmlConfig Custom Action ********************************************************************/ extern "C" UINT __stdcall SchedXmlConfig( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedXmlConfig"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzCurrentFile = NULL; BOOL fCurrentFileChanged = FALSE; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; XML_CONFIG_CHANGE* pxfcHead = NULL; XML_CONFIG_CHANGE* pxfcTail = NULL; // TODO: do we need this any more? XML_CONFIG_CHANGE* pxfc = NULL; eXmlAction xa = xaUnknown; eXmlPreserveDate xd; LPWSTR pwzCustomActionData = NULL; DWORD cFiles = 0; // initialize hr = WcaInitialize(hInstall, "SchedXmlConfig"); ExitOnFailure(hr, "failed to initialize"); hr = ReadXmlConfigTable(&pxfcHead, &pxfcTail); MessageExitOnFailure(hr, msierrXmlConfigFailedRead, "failed to read XmlConfig table"); hr = ProcessChanges(&pxfcHead); ExitOnFailure(hr, "failed to process XmlConfig changes"); // loop through all the xml configurations for (pxfc = pxfcHead; pxfc; pxfc = pxfc->pxfcNext) { // If this is a different file, or the first file... if (NULL == pwzCurrentFile || 0 != lstrcmpW(pwzCurrentFile, pxfc->wzFile)) { // Remember the file we're currently working on hr = StrAllocString(&pwzCurrentFile, pxfc->wzFile, 0); ExitOnFailure(hr, "failed to copy file name"); fCurrentFileChanged = TRUE; } // // Figure out what action to take // xa = xaUnknown; // If it's being installed or reinstalled or uninstalled and that matches // what we are doing then calculate the right action. if ((XMLCONFIG_INSTALL & pxfc->iXmlFlags && (WcaIsInstalling(pxfc->isInstalled, pxfc->isAction) || WcaIsReInstalling(pxfc->isInstalled, pxfc->isAction))) || (XMLCONFIG_UNINSTALL & pxfc->iXmlFlags && WcaIsUninstalling(pxfc->isInstalled, pxfc->isAction))) { if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_ELEMENT & pxfc->iXmlFlags) { xa = xaCreateElement; } else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_ELEMENT & pxfc->iXmlFlags) { xa = xaDeleteElement; } else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_VALUE & pxfc->iXmlFlags) { xa = xaDeleteValue; } else if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_VALUE & pxfc->iXmlFlags) { xa = xaWriteValue; } else if (XMLCONFIG_CREATE & pxfc->iXmlFlags && XMLCONFIG_DOCUMENT & pxfc->iXmlFlags) { xa = xaWriteDocument; } else if (XMLCONFIG_DELETE & pxfc->iXmlFlags && XMLCONFIG_DOCUMENT & pxfc->iXmlFlags) { hr = E_INVALIDARG; ExitOnFailure(hr, "Invalid flag configuration. Cannot delete a fragment node."); } } if (XMLCONFIG_PRESERVE_MODIFIED & pxfc->iXmlFlags) { xd = xdPreserve; } else { xd= xdDontPreserve; } if (xaUnknown != xa) { if (fCurrentFileChanged) { hr = BeginChangeFile(pwzCurrentFile, pxfc->iCompAttributes, &pwzCustomActionData); ExitOnFailure1(hr, "failed to begin file change for file: %ls", pwzCurrentFile); fCurrentFileChanged = FALSE; ++cFiles; } hr = WcaWriteIntegerToCaData((int)xa, &pwzCustomActionData); ExitOnFailure(hr, "failed to write action indicator custom action data"); hr = WcaWriteIntegerToCaData((int)xd, &pwzCustomActionData); ExitOnFailure(hr, "failed to write Preserve Date indicator to custom action data"); hr = WriteChangeData(pxfc, xa, &pwzCustomActionData); ExitOnFailure(hr, "failed to write change data"); } } // 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 < cFiles); hr = WcaDoDeferredAction(PLATFORM_DECORATION(L"ExecXmlConfig"), pwzCustomActionData, cFiles * COST_XMLFILE); ExitOnFailure(hr, "failed to schedule ExecXmlConfig action"); } LExit: ReleaseStr(pwzCurrentFile); ReleaseStr(pwzCustomActionData); FreeXmlConfigChangeList(pxfcHead); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/****************************************************************** SchedSecureObjects - entry point for SchedSecureObjects Custom Action called as Type 1 CustomAction (binary DLL) from Windows Installer in InstallExecuteSequence, to schedule ExecSecureObjects ******************************************************************/ extern "C" UINT __stdcall SchedSecureObjects( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedSecureObjects"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzSecureObject = NULL; LPWSTR pwzData = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzTargetPath = NULL; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; INSTALLSTATE isInstalled; INSTALLSTATE isAction; LPWSTR pwzCustomActionData = NULL; DWORD cObjects = 0; eOBJECTTYPE eType = OT_UNKNOWN; // // initialize // hr = WcaInitialize(hInstall, "SchedSecureObjects"); ExitOnFailure(hr, "failed to initialize"); // anything to do? if (S_OK != WcaTableExists(L"SecureObjects")) { WcaLog(LOGMSG_STANDARD, "SecureObjects table doesn't exist, so there are no objects to secure."); ExitFunction(); } // // 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))) { hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); ExitOnFailure(hr, "failed to get object table"); eType = EObjectTypeFromString(pwzTable); if (OT_UNKNOWN == eType) { ExitOnFailure1(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable); } int iCompAttributes = 0; hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes); ExitOnFailure(hr, "failed to get Component attributes for secure object"); BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; // Only process entries in the SecureObjects table whose components match the bitness of this CA #ifdef _WIN64 if (!fIs64Bit) { continue; } #else if (fIs64Bit) { continue; } #endif // Get the object to secure hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject); ExitOnFailure(hr, "failed to get name of object"); hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath); ExitOnFailure1(hr, "failed to get target path of object '%ls'", pwzSecureObject); hr = WcaGetRecordString(hRec, QSO_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: %ls", pwzData); if (WcaIsInstalling(isInstalled, isAction)) { hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); // add the data to the CustomActionData hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzData); ExitOnFailure(hr, "failed to get name of object"); 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 permission 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(PLATFORM_DECORATION(L"ExecSecureObjects"), pwzCustomActionData, cObjects * COST_SECUREOBJECT); ExitOnFailure(hr, "failed to schedule ExecSecureObjects action"); } LExit: ReleaseStr(pwzSecureObject); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzTable); ReleaseStr(pwzTargetPath); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/****************************************************************** ExecXmlConfigRollback - entry point for XmlConfig rollback Custom Action *******************************************************************/ extern "C" UINT __stdcall ExecXmlConfigRollback( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug ExecXmlConfigRollback"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; int iIs64Bit; BOOL fIs64Bit = FALSE; LPWSTR pwzCustomActionData = NULL; LPWSTR pwz = NULL; LPWSTR pwzFileName = NULL; LPBYTE pbData = NULL; DWORD_PTR cbData = 0; DWORD cbDataWritten = 0; FILETIME ft; HANDLE hFile = INVALID_HANDLE_VALUE; // initialize hr = WcaInitialize(hInstall, "ExecXmlConfigRollback"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadIntegerFromCaData(&pwz, &iIs64Bit); ExitOnFailure(hr, "failed to read component bitness from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzFileName); ExitOnFailure(hr, "failed to read file name from custom action data"); hr = WcaReadStreamFromCaData(&pwz, &pbData, &cbData); ExitOnFailure(hr, "failed to read file contents from custom action data"); fIs64Bit = (BOOL)iIs64Bit; if (fIs64Bit) { hr = WcaInitializeWow64(); if (S_FALSE == hr) { hr = TYPE_E_DLLFUNCTIONNOTFOUND; } ExitOnFailure(hr, "failed to initialize Wow64 API"); if (!WcaIsWow64Process()) { hr = E_NOTIMPL; ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but the Wow64 API is unavailable."); } hr = WcaDisableWow64FSRedirection(); ExitOnFailure(hr, "Custom action was told to rollback a 64-bit component, but was unable to Disable Filesystem Redirection through the Wow64 API."); } hr = FileGetTime(pwzFileName, NULL, NULL, &ft); ExitOnFailure1(hr, "Failed to get modified date of file %ls.", pwzFileName); // Open the file hFile = ::CreateFileW(pwzFileName, GENERIC_WRITE, NULL, NULL, TRUNCATE_EXISTING, NULL, NULL); ExitOnInvalidHandleWithLastError1(hFile, hr, "failed to open file: %ls", pwzFileName); // Write out the old data if (!::WriteFile(hFile, pbData, (DWORD)cbData, &cbDataWritten, NULL)) { ExitOnLastError1(hr, "failed to write to file: %ls", pwzFileName); } Assert(cbData == cbDataWritten); ReleaseFile(hFile); hr = FileSetTime(pwzFileName, NULL, NULL, &ft); ExitOnFailure1(hr, "Failed to set modified date of file %ls.", pwzFileName); LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzFileName); ReleaseFile(hFile); if (fIs64Bit) { WcaRevertWow64FSRedirection(); WcaFinalizeWow64(); } ReleaseMem(pbData); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/****************************************************************** SchedSecureObjectsRollback - entry point for SchedSecureObjectsRollback Custom Action called as Type 1 CustomAction (binary DLL) from Windows Installer in InstallExecuteSequence before SchedSecureObjects ******************************************************************/ extern "C" UINT __stdcall SchedSecureObjectsRollback( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedSecureObjectsRollback"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzSecureObject = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzTargetPath = NULL; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; LPWSTR pwzCustomActionData = NULL; eOBJECTTYPE eType = OT_UNKNOWN; // // initialize // hr = WcaInitialize(hInstall, "SchedSecureObjectsRollback"); 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))) { hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); ExitOnFailure(hr, "failed to get object table"); eType = EObjectTypeFromString(pwzTable); if (OT_UNKNOWN == eType) { ExitOnFailure1(hr = E_INVALIDARG, "unknown SecureObject.Table: %ls", pwzTable); } int iCompAttributes = 0; hr = WcaGetRecordInteger(hRec, QSO_COMPATTRIBUTES, &iCompAttributes); ExitOnFailure(hr, "failed to get Component attributes for secure object"); BOOL fIs64Bit = iCompAttributes & msidbComponentAttributes64bit; // Only process entries in the SecureObjects table whose components match the bitness of this CA #ifdef _WIN64 if (!fIs64Bit) { continue; } #else if (fIs64Bit) { continue; } #endif // get the object being secured that we are planning to schedule rollback for hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject); ExitOnFailure(hr, "failed to get name of object"); hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath); ExitOnFailure1(hr, "failed to get target path of object '%ls' in order to schedule rollback", pwzSecureObject); hr = StoreACLRollbackInfo(pwzTargetPath, pwzTable); if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "Failed to store ACL rollback information with error 0x%x - continuing", hr); } } // 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 schedule rollback for"); LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzSecureObject); ReleaseStr(pwzTable); ReleaseStr(pwzTargetPath); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
/****************************************************************** ExecFirewallExceptions - deferred custom action entry point to register and remove firewall exceptions. ********************************************************************/ extern "C" UINT __stdcall ExecFirewallExceptions( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; BOOL fSupportProfiles = FALSE; LPWSTR pwz = NULL; LPWSTR pwzCustomActionData = NULL; int iTodo = WCA_TODO_UNKNOWN; LPWSTR pwzName = NULL; LPWSTR pwzRemoteAddresses = NULL; int iAttributes = 0; int iTarget = fetUnknown; LPWSTR pwzFile = NULL; LPWSTR pwzPort = NULL; LPWSTR pwzDescription = NULL; int iProtocol = 0; int iProfile = 0; // initialize hr = WcaInitialize(hInstall, "ExecFirewallExceptions"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to initialize COM"); // Find out if we support profiles (only on Vista or later) fSupportProfiles = FSupportProfiles(); // loop through all the passed in data pwz = pwzCustomActionData; while (pwz && *pwz) { // extract the custom action data and if rolling back, swap INSTALL and UNINSTALL hr = WcaReadIntegerFromCaData(&pwz, &iTodo); ExitOnFailure(hr, "failed to read todo from custom action data"); if (::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK)) { if (WCA_TODO_INSTALL == iTodo) { iTodo = WCA_TODO_UNINSTALL; } else if (WCA_TODO_UNINSTALL == iTodo) { iTodo = WCA_TODO_INSTALL; } } hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to read name from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iProfile); ExitOnFailure(hr, "failed to read profile from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzRemoteAddresses); ExitOnFailure(hr, "failed to read remote addresses from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); ExitOnFailure(hr, "failed to read attributes from custom action data"); BOOL fIgnoreFailures = feaIgnoreFailures == (iAttributes & feaIgnoreFailures); hr = WcaReadIntegerFromCaData(&pwz, &iTarget); ExitOnFailure(hr, "failed to read target from custom action data"); if (iTarget == fetApplication) { hr = WcaReadStringFromCaData(&pwz, &pwzFile); ExitOnFailure(hr, "failed to read file path from custom action data"); } hr = WcaReadStringFromCaData(&pwz, &pwzPort); ExitOnFailure(hr, "failed to read port from custom action data"); hr = WcaReadIntegerFromCaData(&pwz, &iProtocol); ExitOnFailure(hr, "failed to read protocol from custom action data"); hr = WcaReadStringFromCaData(&pwz, &pwzDescription); ExitOnFailure(hr, "failed to read protocol from custom action data"); switch (iTarget) { case fetPort: switch (iTodo) { case WCA_TODO_INSTALL: case WCA_TODO_REINSTALL: WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); hr = AddPortException(fSupportProfiles, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription); ExitOnFailure3(hr, "failed to add/update port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); break; case WCA_TODO_UNINSTALL: WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol); hr = RemovePortException(fSupportProfiles, pwzName, pwzPort, iProtocol, fIgnoreFailures); ExitOnFailure3(hr, "failed to remove port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol); break; } break; case fetApplication: switch (iTodo) { case WCA_TODO_INSTALL: case WCA_TODO_REINSTALL: WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls (%ls)", pwzName, pwzFile); hr = AddApplicationException(fSupportProfiles, pwzFile, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription); ExitOnFailure2(hr, "failed to add/update application exception for name '%ls', file '%ls'", pwzName, pwzFile); break; case WCA_TODO_UNINSTALL: WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls (%ls)", pwzName, pwzFile); hr = RemoveApplicationException(fSupportProfiles, pwzName, pwzFile, fIgnoreFailures, pwzPort, iProtocol); ExitOnFailure2(hr, "failed to remove application exception for name '%ls', file '%ls'", pwzName, pwzFile); break; } break; } } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzName); ReleaseStr(pwzRemoteAddresses); ReleaseStr(pwzFile); ReleaseStr(pwzPort); ReleaseStr(pwzDescription); ::CoUninitialize(); return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS); }
/****************************************************************** WixWaitForEvent - entry point for WixWaitForEvent custom action which waits for either the WixWaitForEventFail or WixWaitForEventSucceed named auto reset events. Signaling the WixWaitForEventFail event will return ERROR_INSTALL_FAILURE or signaling the WixWaitForEventSucceed event will return ERROR_SUCCESS. Both events are declared in the Global\ namespace. ********************************************************************/ extern "C" UINT __stdcall WixWaitForEvent( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; HWND hMessageWindow = NULL; LPCWSTR wzSDDL = L"D:(A;;GA;;;WD)"; OS_VERSION version = OS_VERSION_UNKNOWN; DWORD dwServicePack = 0; PSECURITY_DESCRIPTOR pSD = NULL; SECURITY_ATTRIBUTES sa = { }; HANDLE rghEvents[2]; hr = WcaInitialize(hInstall, "WixWaitForEvent"); ExitOnFailure(hr, "Failed to initialize."); // Create a window to prevent shutdown requests. hr = CreateMessageWindow(&hMessageWindow); ExitOnFailure(hr, "Failed to create message window."); // If running on Vista/2008 or newer use integrity enhancements. OsGetVersion(&version, &dwServicePack); if (OS_VERSION_VISTA <= version) { // Add SACL to allow Everyone to signal from a medium integrity level. wzSDDL = L"D:(A;;GA;;;WD)S:(ML;;NW;;;ME)"; } // Create the security descriptor and attributes for the events. if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSDDL, SDDL_REVISION_1, &pSD, NULL)) { ExitWithLastError(hr, "Failed to create the security descriptor for the events."); } sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = FALSE; rghEvents[0] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventFail"); ExitOnNullWithLastError(rghEvents[0], hr, "Failed to create the Global\\WixWaitForEventFail event."); rghEvents[1] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventSucceed"); ExitOnNullWithLastError(rghEvents[1], hr, "Failed to create the Global\\WixWaitForEventSucceed event."); // Wait for either of the events to be signaled and handle accordingly. er = ::WaitForMultipleObjects(countof(rghEvents), rghEvents, FALSE, INFINITE); switch (er) { case WAIT_OBJECT_0 + 0: er = ERROR_INSTALL_FAILURE; break; case WAIT_OBJECT_0 + 1: er = ERROR_SUCCESS; break; default: ExitOnWin32Error(er, hr, "Unexpected failure."); } LExit: ReleaseHandle(rghEvents[1]); ReleaseHandle(rghEvents[0]); if (pSD) { ::LocalFree(pSD); } if (hMessageWindow) { CloseMessageWindow(hMessageWindow); } if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }