/** * \par Implementation * The center of the implementation is the <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa370134%28v=vs.85%29.aspx">MsiGetProperty function</a>. */ Property::operator std::wstring() const { /* * The first call gets the size, but also the actual value if it's short enough. * A second call, if necessary, allocates a sufficiently-long buffer and then gets the full value. * We use only a modest fixed-size buffer for the first step, because we handle arbitrary-length property values in a second step. */ // This buffer allocates on the stack, so we don't want it too large; 64 characters is enough for most properties anyway. WCHAR buffer1[64] = {L'\0'}; DWORD length = sizeof(buffer1) / sizeof(WCHAR); UINT x = MsiGetPropertyW(handle, name.c_str(), buffer1, & length); switch (x) { case ERROR_SUCCESS: // This call might succeed, which means the return value was short enough to fit into the buffer. return std::wstring(buffer1, length); case ERROR_MORE_DATA: // Do nothing yet. break; default: throw WindowsApiError("MsiGetPropertyW", x, "fixed buffer"); } // Assert we received ERROR_MORE_DATA // unique_ptr handles deallocation transparently std::unique_ptr<WCHAR[]> buffer2(new WCHAR[length]); x = MsiGetPropertyW(handle, name.c_str(), buffer2.get(), & length); switch (x) { case ERROR_SUCCESS: return std::wstring(buffer2.get(), length); default: throw WindowsApiError("MsiGetPropertyW", x, "allocated buffer"); } }
UINT __stdcall uninstallLoopbackMSI (MSIHANDLE hInstall) { LPWSTR szValueBuf; DWORD cbValueBuf = 256; Args args; UINT rc; SetMsiReporter("RemoveLoopback", "Removing loopback adapter", hInstall); szValueBuf = (LPWSTR) malloc (cbValueBuf * sizeof (WCHAR)); while (rc = MsiGetPropertyW(hInstall, L"CustomActionData", szValueBuf, &cbValueBuf)) { free (szValueBuf); if (rc == ERROR_MORE_DATA) { cbValueBuf++; szValueBuf = (LPWSTR) malloc (cbValueBuf * sizeof (WCHAR)); } else return ERROR_INSTALL_FAILURE; } if (!process_args(szValueBuf, 1, args)) return ERROR_INSTALL_FAILURE; rc = UnInstallLoopBack (); if (rc == 1) return ERROR_INSTALL_FAILURE; if (rc == 2) { MsiDoActionW (hInstall, L"ScheduleReboot"); } return ERROR_SUCCESS; }
UINT VBoxGetProperty(MSIHANDLE a_hModule, WCHAR *a_pwszName, WCHAR *a_pwszValue, DWORD a_dwSize) { DWORD dwBuffer = 0; UINT uiRet = MsiGetPropertyW(a_hModule, a_pwszName, L"", &dwBuffer); if (uiRet == ERROR_MORE_DATA) { ++dwBuffer; /* On output does not include terminating null, so add 1. */ if (dwBuffer > a_dwSize) return ERROR_MORE_DATA; ZeroMemory(a_pwszValue, a_dwSize); uiRet = MsiGetPropertyW(a_hModule, a_pwszName, a_pwszValue, &dwBuffer); } return uiRet; }
static UINT vboxNetFltQueryInfArray(MSIHANDLE hModule, OUT LPWSTR pwszPtInf, OUT LPWSTR pwszMpInf, DWORD dwSize) { DWORD dwBuf = dwSize - RT_MAX(sizeof(NETFLT_PT_INF_REL_PATH), sizeof(NETFLT_MP_INF_REL_PATH)); UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", pwszPtInf, &dwBuf); if ( uErr == ERROR_SUCCESS && dwBuf) { wcscpy(pwszMpInf, pwszPtInf); wcsncat(pwszPtInf, NETFLT_PT_INF_REL_PATH, sizeof(NETFLT_PT_INF_REL_PATH)); logStringW(hModule, L"vboxNetFltQueryInfArray: INF 1: %s", pwszPtInf); wcsncat(pwszMpInf, NETFLT_MP_INF_REL_PATH, sizeof(NETFLT_MP_INF_REL_PATH)); logStringW(hModule, L"vboxNetFltQueryInfArray: INF 2: %s", pwszMpInf); } else if (uErr != ERROR_SUCCESS) logStringW(hModule, L"vboxNetFltQueryInfArray: MsiGetPropertyW failed, error = 0x%x", uErr); else { logStringW(hModule, L"vboxNetFltQueryInfArray: Empty installation directory"); uErr = ERROR_GEN_FAILURE; } return uErr; }
UINT mccPostInstall(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; hr = WcaInitialize(hInstall, "MccPostInstall"); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); TCHAR INSTALLDIR[1024]; DWORD INSTALLDIR_size = sizeof(INSTALLDIR); TCHAR path[MAX_PATH * 2]; TCHAR param[MAX_PATH * 2]; if(MsiGetPropertyW(hInstall, TEXT("CustomActionData"), INSTALLDIR, &INSTALLDIR_size) == ERROR_SUCCESS) { WcaLog(LOGMSG_STANDARD, "INSTALLDIR = %ls", INSTALLDIR); // C:\Program Files (x86)\MySQL\MySQL Cluster 7.2\share\mcc wcscpy_s(path, MAX_PATH * 2, INSTALLDIR); wcscat_s(path, MAX_PATH * 2, TEXT("\\share\\mcc\\Python\\python.exe")); wcscpy_s(param, MAX_PATH * 2, INSTALLDIR); wcscat_s(param, MAX_PATH * 2, TEXT("\\share\\mcc\\post-install.py")); er = RunProcess(path, param, NULL); } else { er = ERROR_CANT_ACCESS_FILE; } LExit: return WcaFinalize(er); }
/* Check whether the TARGETDIR exists and is a directory. * Set TargetExists appropriately. */ UINT __declspec(dllexport) __stdcall CheckDir(MSIHANDLE hInstall) { #define PSIZE 1024 WCHAR wpath[PSIZE]; char path[PSIZE]; UINT result; DWORD size = PSIZE; DWORD attributes; result = MsiGetPropertyW(hInstall, L"TARGETDIR", wpath, &size); if (result != ERROR_SUCCESS) return result; wpath[size] = L'\0'; path[size] = L'\0'; attributes = GetFileAttributesW(wpath); if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) { return MsiSetPropertyA(hInstall, "TargetExists", "0"); } else { return MsiSetPropertyA(hInstall, "TargetExists", "1"); } }
/* Check for if directory is empty during install, sets "<PROPERTY>_NOT_EMPTY" otherise */ extern "C" UINT __stdcall CheckDirectoryEmpty(MSIHANDLE hInstall, const wchar_t *PropertyName) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; hr = WcaInitialize(hInstall, __FUNCTION__); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); wchar_t buf[MAX_PATH]; DWORD len = MAX_PATH; MsiGetPropertyW(hInstall, PropertyName, buf, &len); wcscat_s(buf, MAX_PATH, L"*.*"); WcaLog(LOGMSG_STANDARD, "Checking files in %S", buf); WIN32_FIND_DATAW data; HANDLE h; bool empty; h= FindFirstFile(buf, &data); if (h != INVALID_HANDLE_VALUE) { empty= true; for(;;) { if (wcscmp(data.cFileName, L".") || wcscmp(data.cFileName, L"..")) { empty= false; break; } if (!FindNextFile(h, &data)) break; } FindClose(h); } else { /* Non-existent directory, we handle it as empty */ empty = true; } if(empty) WcaLog(LOGMSG_STANDARD, "Directory %S is empty or non-existent", PropertyName); else WcaLog(LOGMSG_STANDARD, "Directory %S is NOT empty", PropertyName); wcscpy_s(buf, MAX_PATH, PropertyName); wcscat_s(buf, L"NOTEMPTY"); WcaSetProperty(buf, empty? L"":L"1"); LExit: return WcaFinalize(er); }
/* Sets Innodb buffer pool size (1/8 of RAM by default), if not already specified via command line. Calculates innodb log file size as min(50, innodb buffer pool size/8) */ extern "C" UINT __stdcall PresetDatabaseProperties(MSIHANDLE hInstall) { unsigned long long InnodbBufferPoolSize= 256; unsigned long long InnodbLogFileSize= 50; wchar_t buff[MAX_PATH]; UINT er = ERROR_SUCCESS; HRESULT hr= S_OK; MEMORYSTATUSEX memstatus; hr = WcaInitialize(hInstall, __FUNCTION__); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); /* Check if bufferpoolsize parameter was given on the command line*/ DWORD BufferPoolsizeParamLen = MAX_PATH; MsiGetPropertyW(hInstall, L"BUFFERPOOLSIZE", buff, &BufferPoolsizeParamLen); if (BufferPoolsizeParamLen && buff[0]) { WcaLog(LOGMSG_STANDARD, "BUFFERPOOLSIZE=%s, len=%u",buff, BufferPoolsizeParamLen); InnodbBufferPoolSize= _wtoi64(buff); } else { memstatus.dwLength = sizeof(memstatus); if (!GlobalMemoryStatusEx(&memstatus)) { WcaLog(LOGMSG_STANDARD, "Error %u from GlobalMemoryStatusEx", GetLastError()); er= ERROR_INSTALL_FAILURE; goto LExit; } unsigned long long totalPhys= memstatus.ullTotalPhys; /* Give innodb 12.5% of available physical memory. */ InnodbBufferPoolSize= totalPhys/ONE_MB/8; #ifdef _M_IX86 /* For 32 bit processes, take virtual address space limitation into account. Do not try to use more than 3/4 of virtual address space, even if there is plenty of physical memory. */ InnodbBufferPoolSize= min(GetMaxBufferSize(totalPhys)/ONE_MB*3/4, InnodbBufferPoolSize); #endif swprintf_s(buff, L"%llu",InnodbBufferPoolSize); MsiSetPropertyW(hInstall, L"BUFFERPOOLSIZE", buff); } InnodbLogFileSize = min(50, InnodbBufferPoolSize); swprintf_s(buff, L"%llu",InnodbLogFileSize); MsiSetPropertyW(hInstall, L"LOGFILESIZE", buff); LExit: return WcaFinalize(er); }
extern "C" UINT __stdcall RemoveDataDirectory(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; hr = WcaInitialize(hInstall, __FUNCTION__); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); wchar_t dir[MAX_PATH]; DWORD len = MAX_PATH; MsiGetPropertyW(hInstall, L"CustomActionData", dir, &len); er= ExecRemoveDataDirectory(dir); WcaLog(LOGMSG_STANDARD, "SHFileOperation returned %d", er); LExit: return WcaFinalize(er); }
/* Remove service and data directory created by CreateDatabase operation */ extern "C" UINT __stdcall CreateDatabaseRollback(MSIHANDLE hInstall) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; wchar_t* service= 0; wchar_t* dir= 0; hr = WcaInitialize(hInstall, __FUNCTION__); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); wchar_t data[2*MAX_PATH]; DWORD len= MAX_PATH; MsiGetPropertyW(hInstall, L"CustomActionData", data, &len); /* Property is encoded as [SERVICENAME]\[DBLOCATION] */ if(data[0] == L'\\') { dir= data+1; } else { service= data; dir= wcschr(data, '\\'); if (dir) { *dir=0; dir++; } } if(service) { ExecRemoveService(service); } if(dir) { ExecRemoveDataDirectory(dir); } LExit: return WcaFinalize(er); }
UINT __stdcall installLoopbackMSI (MSIHANDLE hInstall) { LPWSTR szValueBuf; DWORD cbValueBuf = 256; Args args; UINT rc; SetMsiReporter("InstallLoopback", "Installing loopback adapter", hInstall); /* check if there is already one installed. If there is, we shouldn't try to * install another. */ if(IsLoopbackInstalled()) return ERROR_SUCCESS; szValueBuf = (LPWSTR) malloc (cbValueBuf * sizeof (WCHAR)); while (rc = MsiGetPropertyW(hInstall, L"CustomActionData", szValueBuf, &cbValueBuf)) { free (szValueBuf); if (rc == ERROR_MORE_DATA) { cbValueBuf++; szValueBuf = (LPWSTR) malloc (cbValueBuf * sizeof (WCHAR)); } else return ERROR_INSTALL_FAILURE; } if (!process_args(szValueBuf, 1, args)) return ERROR_INSTALL_FAILURE; rc = InstallLoopBack (args.lpConnectionName, args.lpIPAddr, args.lpSubnetMask); if (rc != 2 && rc != 0) return ERROR_INSTALL_FAILURE; if (rc == 2) { MsiDoActionW (hInstall, L"ScheduleReboot"); } return ERROR_SUCCESS; }
UINT wrap(MSIHANDLE hInstall, char *name, int check_only) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; hr = WcaInitialize(hInstall, name); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); TCHAR INSTALLDIR[1024]; DWORD INSTALLDIR_size = sizeof(INSTALLDIR); if(MsiGetPropertyW(hInstall, TEXT("CustomActionData"), INSTALLDIR, &INSTALLDIR_size) == ERROR_SUCCESS) { int rc = remove_service(INSTALLDIR, check_only); if(rc < 0) { er = ERROR_CANCELLED; } } else { er = ERROR_CANT_ACCESS_FILE; } LExit: return WcaFinalize(er); }
UINT __stdcall CreateHostOnlyInterface(MSIHANDLE hModule) { #ifdef VBOX_WITH_NETFLT netCfgLoggerEnable(hModule); BOOL bSetupModeInteractive = SetupSetNonInteractiveMode(FALSE); bool bSetStaticIp = true; logStringW(hModule, L"CreateHostOnlyInterface: Creating host-only interface"); HRESULT hr; GUID guid; WCHAR wszMpInf[MAX_PATH]; DWORD cchMpInf = RT_ELEMENTS(wszMpInf) - sizeof("VBoxNetAdp.inf") - 1; LPCWSTR pwszInfPath = NULL; bool bIsFile = false; UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszMpInf, &cchMpInf); if (uErr == ERROR_SUCCESS) { if (cchMpInf) { logStringW(hModule, L"CreateHostOnlyInterface: NetAdpDir property = %s", wszMpInf); if (wszMpInf[cchMpInf - 1] != L'\\') { wszMpInf[cchMpInf++] = L'\\'; wszMpInf[cchMpInf] = L'\0'; } wcscat(wszMpInf, L"VBoxNetAdp.inf"); pwszInfPath = wszMpInf; bIsFile = true; logStringW(hModule, L"CreateHostOnlyInterface: Resulting INF path = %s", pwszInfPath); } else logStringW(hModule, L"CreateHostOnlyInterface: VBox installation path is empty"); } else logStringW(hModule, L"CreateHostOnlyInterface: Unable to retrieve VBox installation path, error = 0x%x", uErr); /* Make sure the inf file is installed. */ if (pwszInfPath != NULL && bIsFile) { logStringW(hModule, L"CreateHostOnlyInterface: Calling VBoxDrvCfgInfInstall(%s)", pwszInfPath); hr = VBoxDrvCfgInfInstall(pwszInfPath); logStringW(hModule, L"CreateHostOnlyInterface: VBoxDrvCfgInfInstall returns 0x%x", hr); if (FAILED(hr)) logStringW(hModule, L"CreateHostOnlyInterface: Failed to install INF file, error = 0x%x", hr); } if (SUCCEEDED(hr)) { //first, try to update Host Only Network Interface BOOL fRebootRequired = FALSE; hr = VBoxNetCfgWinUpdateHostOnlyNetworkInterface(pwszInfPath, &fRebootRequired); if (SUCCEEDED(hr)) { if (fRebootRequired) { logStringW(hModule, L"UpdateHostOnlyInterfaces: Reboot required, setting REBOOT property to force"); HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force"); if (hr2 != ERROR_SUCCESS) logStringW(hModule, L"UpdateHostOnlyInterfaces: Failed to set REBOOT property, error = 0x%x", hr2); } } else logStringW(hModule, L"UpdateHostOnlyInterfaces: VBoxNetCfgWinUpdateHostOnlyNetworkInterface failed, hr = 0x%x", hr); //in fail case call CreateHostOnlyInterface if (FAILED(hr)) { logStringW(hModule, L"CreateHostOnlyInterface: calling VBoxNetCfgWinCreateHostOnlyNetworkInterface"); hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, bIsFile, &guid, NULL, NULL); logStringW(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface returns 0x%x", hr); if (SUCCEEDED(hr)) { ULONG ip = inet_addr("192.168.56.1"); ULONG mask = inet_addr("255.255.255.0"); logStringW(hModule, L"CreateHostOnlyInterface: calling VBoxNetCfgWinEnableStaticIpConfig"); hr = VBoxNetCfgWinEnableStaticIpConfig(&guid, ip, mask); logStringW(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig returns 0x%x", hr); if (FAILED(hr)) logStringW(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinEnableStaticIpConfig failed, error = 0x%x", hr); } else logStringW(hModule, L"CreateHostOnlyInterface: VBoxNetCfgWinCreateHostOnlyNetworkInterface failed, error = 0x%x", hr); } } if (SUCCEEDED(hr)) logStringW(hModule, L"CreateHostOnlyInterface: Creating host-only interface done"); /* Restore original setup mode. */ logStringW(hModule, L"CreateHostOnlyInterface: Almost done..."); if (bSetupModeInteractive) SetupSetNonInteractiveMode(bSetupModeInteractive); netCfgLoggerDisable(); #endif /* VBOX_WITH_NETFLT */ logStringW(hModule, L"CreateHostOnlyInterface: Returns success (ignoring all failures)"); /* Never fail the install even if we did not succeed. */ return ERROR_SUCCESS; }
UINT __stdcall UpdateHostOnlyInterfaces(MSIHANDLE hModule) { #ifdef VBOX_WITH_NETFLT netCfgLoggerEnable(hModule); logStringW(hModule, L"UpdateHostOnlyInterfaces: Updating all host-only interfaces"); BOOL bSetupModeInteractive = SetupSetNonInteractiveMode(FALSE); WCHAR wszMpInf[MAX_PATH]; DWORD cchMpInf = RT_ELEMENTS(wszMpInf) - sizeof("VBoxNetAdp.inf") - 1; LPCWSTR pwszInfPath = NULL; bool bIsFile = false; UINT uErr = MsiGetPropertyW(hModule, L"CustomActionData", wszMpInf, &cchMpInf); if (uErr == ERROR_SUCCESS) { if (cchMpInf) { logStringW(hModule, L"UpdateHostOnlyInterfaces: NetAdpDir property = %s", wszMpInf); if (wszMpInf[cchMpInf - 1] != L'\\') { wszMpInf[cchMpInf++] = L'\\'; wszMpInf[cchMpInf] = L'\0'; } wcscat(wszMpInf, L"VBoxNetAdp.inf"); pwszInfPath = wszMpInf; bIsFile = true; logStringW(hModule, L"UpdateHostOnlyInterfaces: Resulting INF path = %s", pwszInfPath); DWORD attrFile = GetFileAttributesW(pwszInfPath); if (attrFile == INVALID_FILE_ATTRIBUTES) { DWORD dwErr = GetLastError(); logStringW(hModule, L"UpdateHostOnlyInterfaces: File \"%s\" not found, dwErr=%ld", pwszInfPath, dwErr); } else { logStringW(hModule, L"UpdateHostOnlyInterfaces: File \"%s\" exists", pwszInfPath); BOOL fRebootRequired = FALSE; HRESULT hr = VBoxNetCfgWinUpdateHostOnlyNetworkInterface(pwszInfPath, &fRebootRequired); if (SUCCEEDED(hr)) { if (fRebootRequired) { logStringW(hModule, L"UpdateHostOnlyInterfaces: Reboot required, setting REBOOT property to force"); HRESULT hr2 = MsiSetPropertyW(hModule, L"REBOOT", L"Force"); if (hr2 != ERROR_SUCCESS) logStringW(hModule, L"UpdateHostOnlyInterfaces: Failed to set REBOOT property, error = 0x%x", hr2); } } else logStringW(hModule, L"UpdateHostOnlyInterfaces: VBoxNetCfgWinUpdateHostOnlyNetworkInterface failed, hr = 0x%x", hr); } } else logStringW(hModule, L"UpdateHostOnlyInterfaces: VBox installation path is empty"); } else logStringW(hModule, L"UpdateHostOnlyInterfaces: Unable to retrieve VBox installation path, error = 0x%x", uErr); /* Restore original setup mode. */ if (bSetupModeInteractive) SetupSetNonInteractiveMode(bSetupModeInteractive); netCfgLoggerDisable(); #endif /* VBOX_WITH_NETFLT */ /* Never fail the install even if we did not succeed. */ return ERROR_SUCCESS; }
////////////////////////////////////////////////////////////////////////////// // RemoveUserAccount // // Attempts to remove a user account on the local machine according // to the "instructions" provided in the CustomActionData property // // As a deferred custom action, you do not have access to the database. // The only source of information comes from a property that an immediate // custom action can set to provide the information you need. This // property is written into the script // UINT __stdcall RemoveUserAccount(MSIHANDLE hInstall) { // determine mode in which we are called BOOL bRollback = MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK); // true for rollback, else regular deferred version (for uninstall) BOOL fSuccess = FALSE; // id's for error and warning messages const int iRemoveError = 25003; const int iRemoveWarning = 25004; // Grab the CustomActionData property DWORD cchCAData = 0; if (ERROR_MORE_DATA == MsiGetPropertyW(hInstall, IPROPNAME_CUSTOMACTIONDATA, L"", &cchCAData)) { WCHAR* wszCAData = new WCHAR[++cchCAData]; // add 1 for null-terminator which is not included in size on return if (wszCAData) { if (ERROR_SUCCESS == MsiGetPropertyW(hInstall, IPROPNAME_CUSTOMACTIONDATA, wszCAData, &cchCAData)) { // send ActionData message (template in ActionText table) // send ActionData message (template in ActionText table) PMSIHANDLE hRec = MsiCreateRecord(1); if (!hRec || ERROR_SUCCESS != MsiRecordSetStringW(hRec, 1, wszCAData)) { delete [] wszCAData; return ERROR_INSTALL_FAILURE; } int iRet = MsiProcessMessage(hInstall, INSTALLMESSAGE_ACTIONDATA, hRec); if (IDCANCEL == iRet || IDABORT == iRet) { delete [] wszCAData; return ERROR_INSTALL_USEREXIT; } // // Call the NetUserDel function, // NET_API_STATUS nStatus = NetUserDel(NULL /*local machine*/, wszCAData /*user name*/); if (NERR_Success != nStatus) { PMSIHANDLE hRecErr = MsiCreateRecord(3); if ( !hRecErr || ERROR_SUCCESS != MsiRecordSetStringW(hRecErr, 2, wszCAData)) { delete [] wszCAData; return ERROR_INSTALL_FAILURE; } // In rollback mode, NERR_UserNotFound means cancel button depressed in middle of deferred CA trying to create this account if (bRollback && NERR_UserNotFound == nStatus) { fSuccess = TRUE; } else if (NERR_UserNotFound == nStatus) { // treat this as a warning, but success since we are attempting to delete and it is not present if (ERROR_SUCCESS != MsiRecordSetInteger(hRecErr, 1, iRemoveWarning)) { delete [] wszCAData; return ERROR_INSTALL_FAILURE; } // just pop up an OK button // OPTIONALLY, could specify multiple buttons and cancel // install based on user selection by handling the return value // from MsiProcessMessage, but here we are ignoring the MsiProcessMessage return MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING|MB_ICONWARNING|MB_OK), hRecErr); fSuccess = TRUE; } else { if (ERROR_SUCCESS == MsiRecordSetInteger(hRecErr, 1, iRemoveError) && ERROR_SUCCESS == MsiRecordSetInteger(hRecErr, 3, nStatus)) { // returning failure anyway, so ignoring MsiProcessMessage return MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecErr); } } } else // NERR_Success { fSuccess = TRUE; } } delete [] wszCAData; } } return fSuccess ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; }
UINT __stdcall SavePW(MSIHANDLE hInstall) { HANDLE handle; DWORD size; WCHAR wbuffer[BUFFSIZE + 1] = {}; WCHAR *pw; WCHAR path[MAX_PATH] = {}; DATA_BLOB blob; DATA_BLOB blob_out; DATA_BLOB entropy; int res; size = BUFFSIZE; /* Custom Action Data should be "[CommonAppDataFolder];[GENEDPW]" */ res = MsiGetPropertyW(hInstall, L"CustomActionData", wbuffer, &size); if(res != ERROR_SUCCESS) { pacifica_msi_log(hInstall, TEXT("Failed to get CustomActionData property. %lu %lu."), res, GetLastError()); return ERROR_INSTALL_FAILURE; } //DEBUGGING //pacifica_msi_log(hInstall, TEXT("Got CustomActionData.")); /* Find a pointer to the first ';' in CustomActionData */ pw = wcschr(wbuffer, L';'); /* Null terminate after CommonAppDataFolder */ *pw = L'\0'; /* Advance to the beginning of the password */ pw++; /* Put CommonAppDataFolder in path */ wcscpy(path, wbuffer); /* Full path to password file */ wcscat(path, L"Pacifica\\Uploader\\priv\\localservice.cred"); //DEBUGGING //pacifica_msi_log(hInstall, TEXT("Got Path %s"), path); handle = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(handle == INVALID_HANDLE_VALUE) { pacifica_msi_log(hInstall, TEXT("Failed to open password cred file. %s %lu."), path, GetLastError()); return ERROR_INSTALL_FAILURE; } /* Put password in blob */ blob.cbData = wcslen(pw) * sizeof(WCHAR); blob.pbData = (void*)pw; entropy.pbData = (void*)"a*5%K!M0jn,(vJ19Kz/.nf9031"; entropy.cbData = wcslen(((WCHAR*)entropy.pbData)); /* Encrypt password blob */ res = CryptProtectData(&blob, NULL, &entropy, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &blob_out); if(!res) { pacifica_msi_log(hInstall, TEXT("Failed to crypt data. %lu."), GetLastError()); return ERROR_INSTALL_FAILURE; } /* Write encrypted password blob to file */ WriteFile(handle, blob_out.pbData, blob_out.cbData, &size, NULL); /* Cleanup */ CloseHandle(handle); LocalFree(blob_out.pbData); return ERROR_SUCCESS; }
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); }
/* 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); }