// This checks if file is located on local drive // (has "file://" prefix, or "\\server\share\..." or "X:\path\...") // and set asPathOrUrl back to local path (if prefix was specified) bool CConEmuUpdate::IsLocalFile(LPCWSTR& asPathOrUrl) { LPWSTR psz = (LPWSTR)asPathOrUrl; bool lbLocal = IsLocalFile(psz); asPathOrUrl = psz; return lbLocal; }
BOOL CConEmuUpdate::DownloadFile(LPCWSTR asSource, LPCWSTR asTarget, HANDLE hDstFile, DWORD& crc, BOOL abPackage /*= FALSE*/) { BOOL lbRc = FALSE, lbRead = FALSE, lbWrite = FALSE; CEDownloadErrorArg args[4]; mn_InternetContentReady = 0; // This implies Inet.Deinit(false) too if (!Inet.Init(this)) { // Ошибка уже в стеке goto wrap; } mb_InetMode = !IsLocalFile(asSource); if (mb_InetMode) { mb_DroppedMode = false; if (mp_Set->isUpdateUseProxy) { args[0].argType = at_Str;args[0].strArg = mp_Set->szUpdateProxy; args[1].argType = at_Str;args[1].strArg = mp_Set->szUpdateProxyUser; args[2].argType = at_Str;args[2].strArg = mp_Set->szUpdateProxyPassword; Inet.DownloadCommand(dc_SetProxy, 3, args); } } Inet.SetCallback(dc_ProgressCallback, ProgressCallback, (LPARAM)this); args[0].argType = at_Str; args[0].strArg = asSource; args[1].argType = at_Str; args[1].strArg = asTarget; args[2].argType = at_Uint; args[2].uintArg = (DWORD_PTR)hDstFile; args[3].argType = at_Uint; args[3].uintArg = (mb_ManualCallMode || abPackage); lbRc = Inet.DownloadCommand(dc_DownloadFile, 4, args); if (lbRc) { // args[0].uintArg - contains downloaded size crc = args[1].uintArg; } wrap: Inet.SetCallback(dc_ProgressCallback, NULL, 0); return lbRc; }
/** * Processes a software update command * * @param argc The number of arguments in argv * @param argv The arguments normally passed to updater.exe * argv[0] must be the path to updater.exe * @return TRUE if the update was successful. */ BOOL ProcessSoftwareUpdateCommand(DWORD argc, LPWSTR *argv) { BOOL result = TRUE; if (argc < 3) { LOG_WARN(("Not enough command line parameters specified. " "Updating update.status.")); // We can only update update.status if argv[1] exists. argv[1] is // the directory where the update.status file exists. if (argc < 2 || !WriteStatusFailure(argv[1], SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS)) { LOG_WARN(("Could not write update.status service update failure. (%d)", GetLastError())); } return FALSE; } WCHAR installDir[MAX_PATH + 1] = {L'\0'}; if (!GetInstallationDir(argc, argv, installDir)) { LOG_WARN(("Could not get the installation directory")); if (!WriteStatusFailure(argv[1], SERVICE_INSTALLDIR_ERROR)) { LOG_WARN(("Could not write update.status for GetInstallationDir failure.")); } return FALSE; } // Make sure the path to the updater to use for the update is local. // We do this check to make sure that file locking is available for // race condition security checks. BOOL isLocal = FALSE; if (!IsLocalFile(argv[0], isLocal) || !isLocal) { LOG_WARN(("Filesystem in path %ls is not supported (%d)", argv[0], GetLastError())); if (!WriteStatusFailure(argv[1], SERVICE_UPDATER_NOT_FIXED_DRIVE)) { LOG_WARN(("Could not write update.status service update failure. (%d)", GetLastError())); } return FALSE; } nsAutoHandle noWriteLock(CreateFileW(argv[0], GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr)); if (INVALID_HANDLE_VALUE == noWriteLock) { LOG_WARN(("Could not set no write sharing access on file. (%d)", GetLastError())); if (!WriteStatusFailure(argv[1], SERVICE_COULD_NOT_LOCK_UPDATER)) { LOG_WARN(("Could not write update.status service update failure. (%d)", GetLastError())); } return FALSE; } // Verify that the updater.exe that we are executing is the same // as the one in the installation directory which we are updating. // The installation dir that we are installing to is installDir. WCHAR installDirUpdater[MAX_PATH + 1] = { L'\0' }; wcsncpy(installDirUpdater, installDir, MAX_PATH); if (!PathAppendSafe(installDirUpdater, L"updater.exe")) { LOG_WARN(("Install directory updater could not be determined.")); result = FALSE; } BOOL updaterIsCorrect; if (result && !VerifySameFiles(argv[0], installDirUpdater, updaterIsCorrect)) { LOG_WARN(("Error checking if the updaters are the same.\n" "Path 1: %ls\nPath 2: %ls", argv[0], installDirUpdater)); result = FALSE; } if (result && !updaterIsCorrect) { LOG_WARN(("The updaters do not match, updater will not run.")); result = FALSE; } if (result) { LOG(("updater.exe was compared successfully to the installation directory" " updater.exe.")); } else { if (!WriteStatusFailure(argv[1], SERVICE_UPDATER_COMPARE_ERROR)) { LOG_WARN(("Could not write update.status updater compare failure.")); } return FALSE; } // Check to make sure the updater.exe module has the unique updater identity. // This is a security measure to make sure that the signed executable that // we will run is actually an updater. HMODULE updaterModule = LoadLibraryEx(argv[0], nullptr, LOAD_LIBRARY_AS_DATAFILE); if (!updaterModule) { LOG_WARN(("updater.exe module could not be loaded. (%d)", GetLastError())); result = FALSE; } else { char updaterIdentity[64]; if (!LoadStringA(updaterModule, IDS_UPDATER_IDENTITY, updaterIdentity, sizeof(updaterIdentity))) { LOG_WARN(("The updater.exe application does not contain the Mozilla" " updater identity.")); result = FALSE; } if (strcmp(updaterIdentity, UPDATER_IDENTITY_STRING)) { LOG_WARN(("The updater.exe identity string is not valid.")); result = FALSE; } FreeLibrary(updaterModule); } if (result) { LOG(("The updater.exe application contains the Mozilla" " updater identity.")); } else { if (!WriteStatusFailure(argv[1], SERVICE_UPDATER_IDENTITY_ERROR)) { LOG_WARN(("Could not write update.status no updater identity.")); } return TRUE; } // Check for updater.exe sign problems BOOL updaterSignProblem = FALSE; #ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK updaterSignProblem = !DoesBinaryMatchAllowedCertificates(installDir, argv[0]); #endif // Only proceed with the update if we have no signing problems if (!updaterSignProblem) { BOOL updateProcessWasStarted = FALSE; if (StartUpdateProcess(argc, argv, installDir, updateProcessWasStarted)) { LOG(("updater.exe was launched and run successfully!")); LogFlush(); // Don't attempt to update the service when the update is being staged. if (!IsUpdateBeingStaged(argc, argv)) { // We might not execute code after StartServiceUpdate because // the service installer will stop the service if it is running. StartServiceUpdate(installDir); } } else { result = FALSE; LOG_WARN(("Error running update process. Updating update.status (%d)", GetLastError())); LogFlush(); // If the update process was started, then updater.exe is responsible for // setting the failure code. If it could not be started then we do the // work. We set an error instead of directly setting status pending // so that the app.update.service.errors pref can be updated when // the callback app restarts. if (!updateProcessWasStarted) { if (!WriteStatusFailure(argv[1], SERVICE_UPDATER_COULD_NOT_BE_STARTED)) { LOG_WARN(("Could not write update.status service update failure. (%d)", GetLastError())); } } } } else { result = FALSE; LOG_WARN(("Could not start process due to certificate check error on " "updater.exe. Updating update.status. (%d)", GetLastError())); // When there is a certificate check error on the updater.exe application, // we want to write out the error. if (!WriteStatusFailure(argv[1], SERVICE_UPDATER_SIGN_ERROR)) { LOG_WARN(("Could not write pending state to update.status. (%d)", GetLastError())); } } return result; }
DWORD CConEmuUpdate::CheckProcInt() { BOOL lbDownloadRc = FALSE, lbExecuteRc = FALSE; LPCWSTR pszUpdateVerLocationSet = mp_Set->UpdateVerLocation(); wchar_t *pszUpdateVerLocation = NULL, *pszLocalPackage = NULL, *pszBatchFile = NULL; bool bTempUpdateVerLocation = false; wchar_t szSection[64], szItem[64]; wchar_t szSourceFull[1024]; wchar_t szTemplFilename[128]; wchar_t *pszSource, *pszEnd, *pszFileName; DWORD nSrcLen, nSrcCRC, nLocalCRC = 0; bool lbSourceLocal; //INT_PTR nShellRc = 0; #ifdef _DEBUG // Чтобы успел сервер проинититься и не ругался под отладчиком... if (!mb_ManualCallMode) Sleep(2500); #endif _ASSERTE(m_UpdateStep==us_NotStarted); m_UpdateStep = us_Check; DeleteBadTempFiles(); //120315 - OK, положим в архив и 64битный гуй //#ifdef _WIN64 //if (mp_Set->UpdateDownloadSetup() == 2) //{ // if (mb_ManualCallMode) // { // ReportError(L"64bit versions of ConEmu may be updated with ConEmuSetup.exe only!", 0); // } // goto wrap; //} //#endif // This implies Inet.Deinit(false) too if (!Inet.Init(this)) { goto wrap; } _wsprintf(ms_CurVersion, SKIPLEN(countof(ms_CurVersion)) L"%02u%02u%02u%s", (MVV_1%100),MVV_2,MVV_3,_T(MVV_4a)); // Загрузить информацию о файлах обновления if (IsLocalFile(pszUpdateVerLocationSet)) { pszUpdateVerLocation = (wchar_t*)pszUpdateVerLocationSet; } else { HANDLE hInfo = NULL; BOOL bInfoRc; DWORD crc; TODO("Было бы хорошо избавиться от *ini-файла* и парсить данные в памяти"); pszUpdateVerLocation = CreateTempFile(mp_Set->szUpdateDownloadPath/*L"%TEMP%"*/, L"ConEmuVersion.ini", hInfo); if (!pszUpdateVerLocation) goto wrap; bTempUpdateVerLocation = true; bInfoRc = DownloadFile(pszUpdateVerLocationSet, pszUpdateVerLocation, hInfo, crc); CloseHandle(hInfo); if (!bInfoRc) { if (!mb_ManualCallMode) { DeleteFile(pszUpdateVerLocation); SafeFree(pszUpdateVerLocation); } goto wrap; } } // Проверить версии _wcscpy_c(szSection, countof(szSection), (mp_Set->isUpdateUseBuilds==1) ? sectionConEmuStable : (mp_Set->isUpdateUseBuilds==3) ? sectionConEmuPreview : sectionConEmuDevel); _wcscpy_c(szItem, countof(szItem), (mp_Set->UpdateDownloadSetup()==1) ? L"location_exe" : L"location_arc"); if (!GetPrivateProfileString(szSection, L"version", L"", ms_NewVersion, countof(ms_NewVersion), pszUpdateVerLocation) || !*ms_NewVersion) { ReportBrokenIni(szSection, L"version", pszUpdateVerLocationSet); goto wrap; } // URL may not contain file name at all, compile it (predefined) _wsprintf(szTemplFilename, SKIPLEN(countof(szTemplFilename)) (mp_Set->UpdateDownloadSetup()==1) ? L"ConEmuSetup.%s.exe" : L"ConEmuPack.%s.7z", ms_NewVersion); if (!GetPrivateProfileString(szSection, szItem, L"", szSourceFull, countof(szSourceFull), pszUpdateVerLocation) || !*szSourceFull) { ReportBrokenIni(szSection, szItem, pszUpdateVerLocationSet); goto wrap; } GetVersionsFromIni(pszUpdateVerLocation, ms_VerOnServer, ms_CurVerInfo); if ((lstrcmpi(ms_NewVersion, ms_CurVersion) <= 0) // Если пользователь отказался от обновления в этом сеансе - не предлагать ту же версию при ежечасных проверках || (!mb_ManualCallMode && (lstrcmp(ms_NewVersion, ms_SkipVersion) == 0))) { // Новых версий нет if (mb_ManualCallMode) { wchar_t szFull[300]; _wsprintf(szFull, SKIPLEN(countof(szFull)) L"Your current ConEmu version is %s\n\n" L"Versions on server\n%s\n\n" L"No newer %s version is available", ms_CurVerInfo, ms_VerOnServer, (mp_Set->isUpdateUseBuilds==1) ? L"stable" : (mp_Set->isUpdateUseBuilds==3) ? L"preview" : L"developer", 0); ReportError(szFull, 0); } if (bTempUpdateVerLocation && pszUpdateVerLocation && *pszUpdateVerLocation) { DeleteFile(pszUpdateVerLocation); SafeFree(pszUpdateVerLocation); } goto wrap; } pszSource = szSourceFull; nSrcLen = wcstoul(pszSource, &pszEnd, 10); if (!nSrcLen || !pszEnd || *pszEnd != L',' || *(pszEnd+1) != L'x') { ReportError(L"Invalid format in version description (size)\n%s", szSourceFull, 0); goto wrap; } mn_PackageSize = nSrcLen; pszSource = pszEnd+2; nSrcCRC = wcstoul(pszSource, &pszEnd, 16); if (!nSrcCRC || !pszEnd || *pszEnd != L',') { ReportError(L"Invalid format in version description (CRC32)\n%s", szSourceFull, 0); goto wrap; } pszSource = pszEnd+1; lbSourceLocal = IsLocalFile(pszSource); if (mb_RequestTerminate) goto wrap; // It returns true, if updating with "exe" installer. if (!Check7zipInstalled()) goto wrap; // Error already reported if (!QueryConfirmation(us_ConfirmDownload, pszSource)) { // Если пользователь отказался от обновления в этом сеансе - не предлагать ту же версию при ежечасных проверках wcscpy_c(ms_SkipVersion, ms_NewVersion); goto wrap; } mn_InternetContentReady = 0; m_UpdateStep = us_Downloading; // May be null, if update package was dropped on ConEmu icon if (gpConEmu && ghWnd) { gpConEmu->UpdateProgress(); } pszFileName = wcsrchr(pszSource, lbSourceLocal ? L'\\' : L'/'); if (!pszFileName) { ReportError(L"Invalid source url\n%s", szSourceFull, 0); goto wrap; } else { // Загрузить пакет обновления pszFileName++; // пропустить слеш HANDLE hTarget = NULL; pszLocalPackage = CreateTempFile(mp_Set->szUpdateDownloadPath, szTemplFilename, hTarget); if (!pszLocalPackage) goto wrap; lbDownloadRc = DownloadFile(pszSource, pszLocalPackage, hTarget, nLocalCRC, TRUE); if (lbDownloadRc) { wchar_t szInfo[2048]; LARGE_INTEGER liSize = {}; if (!GetFileSizeEx(hTarget, &liSize) || liSize.HighPart || liSize.LowPart != nSrcLen) { _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"%s\nRequired size=%u, local size=%u", pszSource, nSrcLen, liSize.LowPart); ReportError(L"Downloaded file does not match\n%s\n%s", pszLocalPackage, szInfo, 0); lbDownloadRc = FALSE; } else if (nLocalCRC != nSrcCRC) { _wsprintf(szInfo, SKIPLEN(countof(szInfo)) L"Required CRC32=x%08X, local CRC32=x%08X", nSrcCRC, nLocalCRC); ReportError(L"Invalid local file\n%s\n%s", pszLocalPackage, szInfo, 0); lbDownloadRc = FALSE; } } CloseHandle(hTarget); if (!lbDownloadRc) goto wrap; } Inet.Deinit(true); if (mb_RequestTerminate) goto wrap; pszBatchFile = CreateBatchFile(pszLocalPackage); if (!pszBatchFile) goto wrap; /* nShellRc = (INT_PTR)ShellExecute(ghWnd, bNeedRunElevation ? L"runas" : L"open", pszBatchFile, NULL, NULL, SW_SHOWMINIMIZED); if (nShellRc <= 32) { ReportError(L"Failed to start update batch\n%s\nError code=%i", pszBatchFile, (int)nShellRc); goto wrap; } */ if (!QueryConfirmation(us_ConfirmUpdate)) { // Если пользователь отказался от обновления в этом сеансе - не предлагать ту же версию при ежечасных проверках wcscpy_c(ms_SkipVersion, ms_NewVersion); goto wrap; } mpsz_PendingPackageFile = pszLocalPackage; pszLocalPackage = NULL; mpsz_PendingBatchFile = pszBatchFile; pszBatchFile = NULL; m_UpdateStep = us_ExitAndUpdate; if (gpConEmu) gpConEmu->RequestExitUpdate(); lbExecuteRc = TRUE; wrap: _ASSERTE(mpsz_DeleteIniFile==NULL); mpsz_DeleteIniFile = NULL; if (bTempUpdateVerLocation && pszUpdateVerLocation) { if (*pszUpdateVerLocation) mpsz_DeleteIniFile = pszUpdateVerLocation; //DeleteFile(pszUpdateVerLocation); else SafeFree(pszUpdateVerLocation); } _ASSERTE(mpsz_DeletePackageFile==NULL); mpsz_DeletePackageFile = NULL; if (pszLocalPackage) { if (*pszLocalPackage && (!lbDownloadRc || (!lbExecuteRc && !mp_Set->isUpdateLeavePackages))) mpsz_DeletePackageFile = pszLocalPackage; //DeleteFile(pszLocalPackage); else SafeFree(pszLocalPackage); } _ASSERTE(mpsz_DeleteBatchFile==NULL); mpsz_DeleteBatchFile = NULL; if (pszBatchFile) { if (*pszBatchFile && !lbExecuteRc) mpsz_DeleteBatchFile = pszBatchFile; //DeleteFile(pszBatchFile); else SafeFree(pszBatchFile); } if (!lbExecuteRc) m_UpdateStep = us_NotStarted; Inet.Deinit(true); mb_InCheckProcedure = FALSE; return 0; }