diff options
author | George Hazan <ghazan@miranda.im> | 2020-10-29 19:21:32 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2020-10-29 19:21:32 +0300 |
commit | 74e691804c25c6174cb619d21b19fb5dc94afa22 (patch) | |
tree | 98625fbff7a1c7da877f208e13d0e49962ddffa1 | |
parent | 21aaad51c5e0bcf7157bd8e37e6e8ee0d1e55525 (diff) |
Plugin Updater: pu_stub utilities moved to mir_app
-rw-r--r-- | include/m_utils.h | 24 | ||||
-rw-r--r-- | libs/win32/mir_app.lib | bin | 208302 -> 210752 bytes | |||
-rw-r--r-- | libs/win64/mir_app.lib | bin | 203928 -> 206406 bytes | |||
-rw-r--r-- | plugins/PluginUpdater/src/DlgListNew.cpp | 6 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/DlgUpdate.cpp | 12 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/Options.cpp | 2 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/Utils.cpp | 339 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/stdafx.h | 11 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/unzipfile.cpp | 8 | ||||
-rw-r--r-- | src/mir_app/mir_app.vcxproj | 1 | ||||
-rw-r--r-- | src/mir_app/mir_app.vcxproj.filters | 3 | ||||
-rw-r--r-- | src/mir_app/src/mir_app.def | 9 | ||||
-rw-r--r-- | src/mir_app/src/mir_app64.def | 9 | ||||
-rw-r--r-- | src/mir_app/src/pu_utils.cpp | 296 |
14 files changed, 367 insertions, 353 deletions
diff --git a/include/m_utils.h b/include/m_utils.h index f2e3095a31..da87379899 100644 --- a/include/m_utils.h +++ b/include/m_utils.h @@ -411,4 +411,28 @@ struct ENTER_STRING EXTERN_C MIR_APP_DLL(bool) EnterString(ENTER_STRING *pForm);
+/////////////////////////////////////////////////////////////////////////////////////////
+// pu_stub utilities
+
+namespace PU
+{
+ // Checks if we're working via pu_stub or not
+ MIR_APP_DLL(bool) IsDirect();
+
+ // Checks if a process has enough rights to write into Miranda's folder
+ MIR_APP_DLL(bool) IsProcessElevated();
+
+ // Launches pu_stub.exe with elevated priviledges if needed
+ MIR_APP_DLL(bool) PrepareEscalation();
+
+ MIR_APP_DLL(int) SafeCopyFile(const wchar_t *pSrc, const wchar_t *pDst);
+ MIR_APP_DLL(int) SafeMoveFile(const wchar_t *pSrc, const wchar_t *pDst);
+ MIR_APP_DLL(int) SafeDeleteFile(const wchar_t *pwszFile);
+ MIR_APP_DLL(int) SafeCreateDirectory(const wchar_t *pwszFolder);
+ MIR_APP_DLL(int) SafeDeleteDirectory(const wchar_t *pwszDirName);
+ MIR_APP_DLL(int) SafeCreateFilePath(const wchar_t *pwszFolder);
+
+
+};
+
#endif // M_UTILS_H__
diff --git a/libs/win32/mir_app.lib b/libs/win32/mir_app.lib Binary files differindex a96077ac5d..d8bff94ffe 100644 --- a/libs/win32/mir_app.lib +++ b/libs/win32/mir_app.lib diff --git a/libs/win64/mir_app.lib b/libs/win64/mir_app.lib Binary files differindex 3cc71cb27b..96b4d8762c 100644 --- a/libs/win64/mir_app.lib +++ b/libs/win64/mir_app.lib diff --git a/plugins/PluginUpdater/src/DlgListNew.cpp b/plugins/PluginUpdater/src/DlgListNew.cpp index b470cff31c..fb6e5b59cd 100644 --- a/plugins/PluginUpdater/src/DlgListNew.cpp +++ b/plugins/PluginUpdater/src/DlgListNew.cpp @@ -162,7 +162,7 @@ public: wcscat(szPath, L".test");
HANDLE hFile = CreateFileW(szPath, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile == INVALID_HANDLE_VALUE)
- Button_SetElevationRequiredState(GetDlgItem(m_hwnd, IDOK), !IsProcessElevated());
+ Button_SetElevationRequiredState(GetDlgItem(m_hwnd, IDOK), !PU::IsProcessElevated());
else {
CloseHandle(hFile);
DeleteFile(szPath);
@@ -311,7 +311,7 @@ public: if (DownloadFile(&p->File, nlc)) {
m_list.SetItemText(i, 1, TranslateT("Succeeded."));
if (!unzip(p->File.wszDiskPath, wszMirandaPath, wszBackupFolder, false))
- SafeDeleteFile(p->File.wszDiskPath); // remove .zip after successful update
+ PU::SafeDeleteFile(p->File.wszDiskPath); // remove .zip after successful update
db_unset(0, DB_MODULE_NEW_FILES, _T2A(p->wszOldName));
}
else m_list.SetItemText(i, 1, TranslateT("Failed!"));
@@ -339,7 +339,7 @@ static void ApplyDownloads(void *param) auto *pDlg = (CMissingPLuginsDlg *)param;
// if we need to escalate priviledges, launch a atub
- if (PrepareEscalation())
+ if (PU::PrepareEscalation())
pDlg->Unpack();
pDlg->Close();
diff --git a/plugins/PluginUpdater/src/DlgUpdate.cpp b/plugins/PluginUpdater/src/DlgUpdate.cpp index dc5a53a527..e79d94bdc4 100644 --- a/plugins/PluginUpdater/src/DlgUpdate.cpp +++ b/plugins/PluginUpdater/src/DlgUpdate.cpp @@ -39,7 +39,7 @@ class CUpdateDLg : public CDlgBase OBJLIST<FILEINFO> todo(*pDlg->m_todo);
// 1) If we need to escalate priviledges, launch a stub
- if (!PrepareEscalation()) {
+ if (!PU::PrepareEscalation()) {
pDlg->Close();
return;
}
@@ -113,7 +113,7 @@ LBL_Error: if (dwErrorCode = unzip(it->File.wszDiskPath, wszMirandaPath, wszBackupFolder, true))
goto LBL_Error;
- SafeDeleteFile(it->File.wszDiskPath); // remove .zip after successful update
+ PU::SafeDeleteFile(it->File.wszDiskPath); // remove .zip after successful update
}
}
}
@@ -134,7 +134,7 @@ LBL_Error: else {
ptrW oldbin(g_plugin.getWStringA("OldBin2"));
if (oldbin) {
- SafeDeleteFile(oldbin);
+ PU::SafeDeleteFile(oldbin);
g_plugin.delSetting("OldBin2");
}
}
@@ -213,7 +213,7 @@ public: HANDLE hFile = CreateFileW(wszPath, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile == INVALID_HANDLE_VALUE)
// Running Windows Vista or later (major version >= 6).
- Button_SetElevationRequiredState(btnOk.GetHwnd(), !IsProcessElevated());
+ Button_SetElevationRequiredState(btnOk.GetHwnd(), !PU::IsProcessElevated());
else {
CloseHandle(hFile);
DeleteFileW(wszPath);
@@ -395,7 +395,7 @@ static void DlgUpdateSilent(void *param) }
// 1) If we need to escalate priviledges, launch a stub
- if (!PrepareEscalation()) {
+ if (!PU::PrepareEscalation()) {
delete &UpdateFiles;
return;
}
@@ -462,7 +462,7 @@ LBL_Error: // remove .zip after successful update
if (dwErrorCode = unzip(it->File.wszDiskPath, wszMirandaPath, wszBackupFolder, true))
goto LBL_Error;
- SafeDeleteFile(it->File.wszDiskPath);
+ PU::SafeDeleteFile(it->File.wszDiskPath);
}
}
}
diff --git a/plugins/PluginUpdater/src/Options.cpp b/plugins/PluginUpdater/src/Options.cpp index c796524d7f..936551f5c6 100644 --- a/plugins/PluginUpdater/src/Options.cpp +++ b/plugins/PluginUpdater/src/Options.cpp @@ -288,7 +288,7 @@ public: FindClose(hFind);
}
- if (PrepareEscalation())
+ if (PU::PrepareEscalation())
RemoveBackupFolders();
// if user tried to change the channel, run the update dialog immediately
diff --git a/plugins/PluginUpdater/src/Utils.cpp b/plugins/PluginUpdater/src/Utils.cpp index 63c1ede5b4..41760a5303 100644 --- a/plugins/PluginUpdater/src/Utils.cpp +++ b/plugins/PluginUpdater/src/Utils.cpp @@ -20,7 +20,6 @@ Boston, MA 02111-1307, USA. #include "stdafx.h"
HNETLIBUSER hNetlibUser = nullptr;
-HANDLE g_hPipe = nullptr;
/////////////////////////////////////////////////////////////////////////////////////
@@ -146,6 +145,8 @@ bool ParseHashes(const wchar_t *pwszUrl, ptrW &baseUrl, SERVLIST &arHashes) return true;
}
+/////////////////////////////////////////////////////////////////////////////////////////
+// Single file HTTP transaction
bool DownloadFile(FILEURL *pFileURL, HNETLIBCONN &nlc)
{
@@ -215,7 +216,7 @@ bool DownloadFile(FILEURL *pFileURL, HNETLIBCONN &nlc) if (hFile != INVALID_HANDLE_VALUE) {
WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, nullptr);
CloseHandle(hFile);
- SafeMoveFile(wszTempFile, pFileURL->wszDiskPath);
+ PU::SafeMoveFile(wszTempFile, pFileURL->wszDiskPath);
}
}
return true;
@@ -232,212 +233,6 @@ bool DownloadFile(FILEURL *pFileURL, HNETLIBCONN &nlc) return false;
}
-/////////////////////////////////////////////////////////////////////////////////////
-// FUNCTION: IsRunAsAdmin()
-//
-// PURPOSE: The function checks whether the current process is run as
-// administrator. In other words, it dictates whether the primary access
-// token of the process belongs to user account that is a member of the
-// local Administrators group and it is elevated.
-//
-// RETURN VALUE: Returns TRUE if the primary access token of the process
-// belongs to user account that is a member of the local Administrators
-// group and it is elevated. Returns FALSE if the token does not.
-//
-// EXCEPTION: If this function fails, it throws a C++ DWORD exception which
-// contains the Win32 error code of the failure.
-//
-// EXAMPLE CALL:
-// try
-// {
-// if (IsRunAsAdmin())
-// wprintf (L"Process is run as administrator\n");
-// else
-// wprintf (L"Process is not run as administrator\n");
-// }
-// catch (DWORD dwError)
-// {
-// wprintf(L"IsRunAsAdmin failed w/err %lu\n", dwError);
-// }
-
-BOOL IsRunAsAdmin()
-{
- BOOL fIsRunAsAdmin = FALSE;
- DWORD dwError = ERROR_SUCCESS;
- PSID pAdministratorsGroup = nullptr;
-
- // Allocate and initialize a SID of the administrators group.
- SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
- if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdministratorsGroup)) {
- dwError = GetLastError();
- goto Cleanup;
- }
-
- // Determine whether the SID of administrators group is bEnabled in
- // the primary access token of the process.
- if (!CheckTokenMembership(nullptr, pAdministratorsGroup, &fIsRunAsAdmin)) {
- dwError = GetLastError();
- goto Cleanup;
- }
-
-Cleanup:
- // Centralized cleanup for all allocated resources.
- if (pAdministratorsGroup) {
- FreeSid(pAdministratorsGroup);
- pAdministratorsGroup = nullptr;
- }
-
- // Throw the error if something failed in the function.
- if (ERROR_SUCCESS != dwError) {
- throw dwError;
- }
-
- return fIsRunAsAdmin;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-// FUNCTION: IsProcessElevated()
-//
-// PURPOSE: The function gets the elevation information of the current
-// process. It dictates whether the process is elevated or not. Token
-// elevation is only available on Windows Vista and newer operating
-// systems, thus IsProcessElevated throws a C++ exception if it is called
-// on systems prior to Windows Vista. It is not appropriate to use this
-// function to determine whether a process is run as administartor.
-//
-// RETURN VALUE: Returns TRUE if the process is elevated. Returns FALSE if
-// it is not.
-//
-// EXCEPTION: If this function fails, it throws a C++ DWORD exception
-// which contains the Win32 error code of the failure. For example, if
-// IsProcessElevated is called on systems prior to Windows Vista, the error
-// code will be ERROR_INVALID_PARAMETER.
-//
-// NOTE: TOKEN_INFORMATION_CLASS provides TokenElevationType to check the
-// elevation type (TokenElevationTypeDefault / TokenElevationTypeLimited /
-// TokenElevationTypeFull) of the process. It is different from
-// TokenElevation in that, when UAC is turned off, elevation type always
-// returns TokenElevationTypeDefault even though the process is elevated
-// (Integrity Level == High). In other words, it is not safe to say if the
-// process is elevated based on elevation type. Instead, we should use
-// TokenElevation.
-//
-// EXAMPLE CALL:
-// try
-// {
-// if (IsProcessElevated())
-// wprintf (L"Process is elevated\n");
-// else
-// wprintf (L"Process is not elevated\n");
-// }
-// catch (DWORD dwError)
-// {
-// wprintf(L"IsProcessElevated failed w/err %lu\n", dwError);
-// }
-
-BOOL IsProcessElevated()
-{
- BOOL fIsElevated = FALSE;
- DWORD dwError = ERROR_SUCCESS;
- HANDLE hToken = nullptr;
-
- // Open the primary access token of the process with TOKEN_QUERY.
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
- dwError = GetLastError();
- goto Cleanup;
- }
-
- // Retrieve token elevation information.
- TOKEN_ELEVATION elevation;
- DWORD dwSize;
- if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize)) {
- // When the process is run on operating systems prior to Windows
- // Vista, GetTokenInformation returns FALSE with the
- // ERROR_INVALID_PARAMETER error code because TokenElevation is
- // not supported on those operating systems.
- dwError = GetLastError();
- goto Cleanup;
- }
-
- fIsElevated = elevation.TokenIsElevated;
-
-Cleanup:
- // Centralized cleanup for all allocated resources.
- if (hToken) {
- CloseHandle(hToken);
- hToken = nullptr;
- }
-
- // Throw the error if something failed in the function.
- if (ERROR_SUCCESS != dwError) {
- throw dwError;
- }
-
- return fIsElevated;
-}
-
-bool PrepareEscalation()
-{
- // First try to create a file near Miranda32.exe
- TFileName szPath;
- GetModuleFileName(nullptr, szPath, _countof(szPath));
- wchar_t *ext = wcsrchr(szPath, '.');
- if (ext != nullptr)
- *ext = '\0';
- wcscat(szPath, L".test");
-
- HANDLE hFile = CreateFile(szPath, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
- if (hFile != INVALID_HANDLE_VALUE) {
- // we are admins or UAC is disable, cool
- CloseHandle(hFile);
- DeleteFile(szPath);
- return true;
- }
-
- // Check the current process's "run as administrator" status.
- if (IsRunAsAdmin())
- return true;
-
- // if pipe already opened?
- if (g_hPipe != nullptr)
- return true;
-
- // Elevate the process. Create a pipe for a stub first
- TFileName wzPipeName;
- mir_snwprintf(wzPipeName, L"\\\\.\\pipe\\Miranda_Pu_%d", GetCurrentProcessId());
- g_hPipe = CreateNamedPipe(wzPipeName, PIPE_ACCESS_DUPLEX, PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, nullptr);
- if (g_hPipe == INVALID_HANDLE_VALUE) {
- g_hPipe = nullptr;
- }
- else {
- wchar_t cmdLine[100], *p;
- GetModuleFileName(nullptr, szPath, ARRAYSIZE(szPath));
- if ((p = wcsrchr(szPath, '\\')) != nullptr)
- wcscpy(p + 1, L"pu_stub.exe");
- mir_snwprintf(cmdLine, L"%d", GetCurrentProcessId());
-
- // Launch a stub
- SHELLEXECUTEINFO sei = { sizeof(sei) };
- sei.lpVerb = L"runas";
- sei.lpFile = szPath;
- sei.lpParameters = cmdLine;
- sei.hwnd = nullptr;
- sei.nShow = SW_NORMAL;
- if (ShellExecuteEx(&sei)) {
- if (g_hPipe != nullptr)
- ConnectNamedPipe(g_hPipe, nullptr);
- return true;
- }
-
- DWORD dwError = GetLastError();
- if (dwError == ERROR_CANCELLED) {
- // The user refused to allow privileges elevation.
- // Do nothing ...
- }
- }
- return false;
-}
-
/////////////////////////////////////////////////////////////////////////////////////////
// Folder creation
@@ -451,10 +246,10 @@ void CreateWorkFolders(TFileName &wszTempFolder, TFileName &wszBackupFolder) SYSTEMTIME st;
GetLocalTime(&st);
mir_snwprintf(wszBackupFolder, L"%s\\Backups\\BKP%04d-%02d-%02d %02d-%02d-%02d-%03d", g_wszRoot, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
- SafeCreateDirectory(wszBackupFolder);
+ PU::SafeCreateDirectory(wszBackupFolder);
mir_snwprintf(wszTempFolder, L"%s\\Temp", g_wszRoot);
- SafeCreateDirectory(wszTempFolder);
+ PU::SafeCreateDirectory(wszTempFolder);
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -480,10 +275,10 @@ void RemoveBackupFolders() FindClose(hFind);
// remove all folders with lesser dates if there're more than 10 folders
- if (PrepareEscalation()) {
+ if (PU::PrepareEscalation()) {
while (arNames.getCount() > g_plugin.iNumberBackups) {
mir_snwprintf(wszMask, L"%s\\Backups\\%s", g_wszRoot, arNames[0].c_str());
- SafeDeleteDirectory(wszMask);
+ PU::SafeDeleteDirectory(wszMask);
arNames.remove(00);
}
}
@@ -512,7 +307,7 @@ static void SafeMoveFolder(const wchar_t *wszSrc, const wchar_t *wszDest) if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
SafeMoveFolder(wszNewSrc, wszNewDest);
else
- SafeMoveFile(wszNewSrc, wszNewDest);
+ PU::SafeMoveFile(wszNewSrc, wszNewDest);
}
while (FindNextFileW(hFind, &fdata));
@@ -524,119 +319,7 @@ void RollbackChanges(TFileName &pwszBackupFolder) VARSW dirname(L"%miranda_path%");
SafeMoveFolder(pwszBackupFolder, dirname);
- SafeDeleteDirectory(pwszBackupFolder);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-int TransactPipe(int opcode, const wchar_t *p1, const wchar_t *p2)
-{
- BYTE buf[1024];
- DWORD l1 = lstrlen(p1), l2 = lstrlen(p2);
- if (l1 > MAX_PATH || l2 > MAX_PATH)
- return ERROR_BAD_ARGUMENTS;
-
- *(DWORD *)buf = opcode;
- wchar_t *dst = (wchar_t *)&buf[sizeof(DWORD)];
- lstrcpy(dst, p1);
- dst += l1 + 1;
- if (p2) {
- lstrcpy(dst, p2);
- dst += l2 + 1;
- }
- else *dst++ = 0;
-
- DWORD dwBytes = 0, dwError;
- if (!WriteFile(g_hPipe, buf, (DWORD)((BYTE *)dst - buf), &dwBytes, nullptr))
- return GetLastError();
-
- dwError = 0;
- if (!ReadFile(g_hPipe, &dwError, sizeof(DWORD), &dwBytes, nullptr))
- return GetLastError();
- if (dwBytes != sizeof(DWORD))
- return ERROR_BAD_ARGUMENTS;
-
- return dwError;
-}
-
-int SafeCopyFile(const wchar_t *pSrc, const wchar_t *pDst)
-{
- if (g_hPipe == nullptr)
- return CopyFileW(pSrc, pDst, FALSE);
-
- return TransactPipe(1, pSrc, pDst);
-}
-
-int SafeMoveFile(const wchar_t *pSrc, const wchar_t *pDst)
-{
- if (g_hPipe == nullptr) {
- if (!DeleteFileW(pDst)) {
- DWORD dwError = GetLastError();
- if (dwError != ERROR_ACCESS_DENIED && dwError != ERROR_FILE_NOT_FOUND)
- return dwError;
- }
-
- if (!MoveFileW(pSrc, pDst)) { // use copy on error
- switch (DWORD dwError = GetLastError()) {
- case ERROR_ALREADY_EXISTS:
- case ERROR_FILE_NOT_FOUND:
- return 0; // this file was included into many archives, so Miranda tries to move it again & again
-
- case ERROR_ACCESS_DENIED:
- case ERROR_SHARING_VIOLATION:
- case ERROR_LOCK_VIOLATION:
- // use copy routine if a move operation isn't available
- // for example, when files are on different disks
- if (!CopyFileW(pSrc, pDst, FALSE))
- return GetLastError();
-
- if (!DeleteFileW(pSrc))
- return GetLastError();
- break;
-
- default:
- return dwError;
- }
- }
-
- return ERROR_SUCCESS;
- }
-
- return TransactPipe(2, pSrc, pDst);
-}
-
-int SafeDeleteFile(const wchar_t *pwszFile)
-{
- if (g_hPipe == nullptr)
- return DeleteFile(pwszFile);
-
- return TransactPipe(3, pwszFile, nullptr);
-}
-
-int SafeCreateDirectory(const wchar_t *pwszFolder)
-{
- if (g_hPipe == nullptr)
- return CreateDirectoryTreeW(pwszFolder);
-
- return TransactPipe(4, pwszFolder, nullptr);
-}
-
-int SafeDeleteDirectory(const wchar_t *pwszDirName)
-{
- if (g_hPipe == nullptr)
- return DeleteDirectoryTreeW(pwszDirName);
-
- return TransactPipe(6, pwszDirName, nullptr);
-}
-
-int SafeCreateFilePath(const wchar_t *pwszFolder)
-{
- if (g_hPipe == nullptr) {
- CreatePathToFileW(pwszFolder);
- return 0;
- }
-
- return TransactPipe(5, pwszFolder, nullptr);
+ PU::SafeDeleteDirectory(pwszBackupFolder);
}
int BackupFile(wchar_t *pwszSrcFileName, wchar_t *pwszBackFileName)
@@ -644,9 +327,9 @@ int BackupFile(wchar_t *pwszSrcFileName, wchar_t *pwszBackFileName) if (_waccess(pwszSrcFileName, 0))
return 0;
- SafeCreateFilePath(pwszBackFileName);
+ PU::SafeCreateFilePath(pwszBackFileName);
- return SafeMoveFile(pwszSrcFileName, pwszBackFileName);
+ return PU::SafeMoveFile(pwszSrcFileName, pwszBackFileName);
}
/////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/PluginUpdater/src/stdafx.h b/plugins/PluginUpdater/src/stdafx.h index 8a0aea883e..db71968ea2 100644 --- a/plugins/PluginUpdater/src/stdafx.h +++ b/plugins/PluginUpdater/src/stdafx.h @@ -153,7 +153,6 @@ using namespace std; extern DWORD g_mirandaVersion;
extern wchar_t g_wszRoot[MAX_PATH], g_wszTempPath[MAX_PATH];
-extern HANDLE g_hPipe;
extern HNETLIBUSER hNetlibUser;
extern IconItem iconList[];
@@ -254,18 +253,8 @@ int unzip(const wchar_t *pwszZipFile, wchar_t *pwszDestPath, wchar_t *pwszBackP int CalculateModuleHash(const wchar_t *pwszFileName, char *dest);
-BOOL IsProcessElevated(void);
-bool PrepareEscalation(void);
-
void CreateWorkFolders(TFileName &wszTempFolder, TFileName &wszBackupFolder);
void RemoveBackupFolders(void);
void RollbackChanges(TFileName &pwszBackupFolder);
-int SafeCreateDirectory(const wchar_t *pwszDirName);
-int SafeDeleteDirectory(const wchar_t *pwszDirName);
-int SafeCopyFile(const wchar_t *pwszSrc, const wchar_t *pwszDst);
-int SafeMoveFile(const wchar_t *pwszSrc, const wchar_t *pwszDst);
-int SafeDeleteFile(const wchar_t *pwszSrc);
-int SafeCreateFilePath(const wchar_t *pFolder);
-
char* StrToLower(char *str);
diff --git a/plugins/PluginUpdater/src/unzipfile.cpp b/plugins/PluginUpdater/src/unzipfile.cpp index fb3bb2ae5a..2dbe754af6 100644 --- a/plugins/PluginUpdater/src/unzipfile.cpp +++ b/plugins/PluginUpdater/src/unzipfile.cpp @@ -66,10 +66,10 @@ int extractCurrentFile(unzFile uf, wchar_t *pwszDestPath, wchar_t *pwszBackPath, }
PrepareFileName(wszDestFile, _countof(wszDestFile), pwszDestPath, pwszNewName);
- SafeCreateFilePath(wszDestFile);
+ PU::SafeCreateFilePath(wszDestFile);
wchar_t *pwszFile2unzip;
- if (g_hPipe == nullptr) // direct mode
+ if (PU::IsDirect())
pwszFile2unzip = wszDestFile;
else {
TFileName wszTempPath;
@@ -103,8 +103,8 @@ int extractCurrentFile(unzFile uf, wchar_t *pwszDestPath, wchar_t *pwszBackPath, CloseHandle(hFile);
unzCloseCurrentFile(uf); /* don't lose the error */
- if (g_hPipe)
- SafeMoveFile(pwszFile2unzip, wszDestFile);
+ if (!PU::IsDirect())
+ PU::SafeMoveFile(pwszFile2unzip, wszDestFile);
}
return err;
}
diff --git a/src/mir_app/mir_app.vcxproj b/src/mir_app/mir_app.vcxproj index 8658ff5b87..0f55a19c5f 100644 --- a/src/mir_app/mir_app.vcxproj +++ b/src/mir_app/mir_app.vcxproj @@ -139,6 +139,7 @@ <ClCompile Include="src\proto_order.cpp" />
<ClCompile Include="src\proto_ui.cpp" />
<ClCompile Include="src\proto_utils.cpp" />
+ <ClCompile Include="src\pu_utils.cpp" />
<ClCompile Include="src\searchresults.cpp" />
<ClCompile Include="src\skin2opts.cpp" />
<ClCompile Include="src\skinicons.cpp" />
diff --git a/src/mir_app/mir_app.vcxproj.filters b/src/mir_app/mir_app.vcxproj.filters index 1db664ca70..a41d536dd7 100644 --- a/src/mir_app/mir_app.vcxproj.filters +++ b/src/mir_app/mir_app.vcxproj.filters @@ -386,6 +386,9 @@ <ClCompile Include="src\chat_ui.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\pu_utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\chat.h">
diff --git a/src/mir_app/src/mir_app.def b/src/mir_app/src/mir_app.def index 0bf07ba1cc..8dabfd30b6 100644 --- a/src/mir_app/src/mir_app.def +++ b/src/mir_app/src/mir_app.def @@ -741,3 +741,12 @@ Chat_CreateMenu @824 NONAME ?GetChecker@MDatabaseCommon@@UAGPAUMIDatabaseChecker@@XZ @829 NONAME
?GetMenuItem@PROTO_INTERFACE@@QAEPAUTMO_IntMenuItem@@W4ProtoMenuItemType@@@Z @830 NONAME
_Netlib_GetTlsUnique@8 @831 NONAME
+?IsDirect@PU@@YG_NXZ @832 NONAME
+?IsProcessElevated@PU@@YG_NXZ @833 NONAME
+?PrepareEscalation@PU@@YG_NXZ @834 NONAME
+?SafeCopyFile@PU@@YGHPB_W0@Z @835 NONAME
+?SafeCreateDirectory@PU@@YGHPB_W@Z @836 NONAME
+?SafeCreateFilePath@PU@@YGHPB_W@Z @837 NONAME
+?SafeDeleteDirectory@PU@@YGHPB_W@Z @838 NONAME
+?SafeDeleteFile@PU@@YGHPB_W@Z @839 NONAME
+?SafeMoveFile@PU@@YGHPB_W0@Z @840 NONAME
diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def index 945587d58a..70a00197d4 100644 --- a/src/mir_app/src/mir_app64.def +++ b/src/mir_app/src/mir_app64.def @@ -741,3 +741,12 @@ Chat_CreateMenu @824 NONAME ?GetChecker@MDatabaseCommon@@UEAAPEAUMIDatabaseChecker@@XZ @829 NONAME
?GetMenuItem@PROTO_INTERFACE@@QEAAPEAUTMO_IntMenuItem@@W4ProtoMenuItemType@@@Z @830 NONAME
Netlib_GetTlsUnique @831 NONAME
+?IsDirect@PU@@YA_NXZ @832 NONAME
+?IsProcessElevated@PU@@YA_NXZ @833 NONAME
+?PrepareEscalation@PU@@YA_NXZ @834 NONAME
+?SafeCopyFile@PU@@YAHPEB_W0@Z @835 NONAME
+?SafeCreateDirectory@PU@@YAHPEB_W@Z @836 NONAME
+?SafeCreateFilePath@PU@@YAHPEB_W@Z @837 NONAME
+?SafeDeleteDirectory@PU@@YAHPEB_W@Z @838 NONAME
+?SafeDeleteFile@PU@@YAHPEB_W@Z @839 NONAME
+?SafeMoveFile@PU@@YAHPEB_W0@Z @840 NONAME
diff --git a/src/mir_app/src/pu_utils.cpp b/src/mir_app/src/pu_utils.cpp new file mode 100644 index 0000000000..f65a0f969c --- /dev/null +++ b/src/mir_app/src/pu_utils.cpp @@ -0,0 +1,296 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-20 Miranda NG team, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +///////////////////////////////////////////////////////////////////////////////////////// +// pu_stub.exe interface + +#include "stdafx.h" + +static HANDLE g_hPipe = nullptr; + +///////////////////////////////////////////////////////////////////////////////////////// +// are we running with admin priviledges? + +static bool IsRunAsAdmin() +{ + BOOL bIsRunAsAdmin = false; + DWORD dwError = ERROR_SUCCESS; + PSID pAdministratorsGroup = nullptr; + + // Allocate and initialize a SID of the administrators group. + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdministratorsGroup)) { + dwError = GetLastError(); + goto Cleanup; + } + + // Determine whether the SID of administrators group is bEnabled in + // the primary access token of the process. + if (!CheckTokenMembership(nullptr, pAdministratorsGroup, &bIsRunAsAdmin)) { + dwError = GetLastError(); + goto Cleanup; + } + +Cleanup: + // Centralized cleanup for all allocated resources. + if (pAdministratorsGroup) { + FreeSid(pAdministratorsGroup); + pAdministratorsGroup = nullptr; + } + + // Throw the error if something failed in the function. + if (ERROR_SUCCESS != dwError) { + throw dwError; + } + + return bIsRunAsAdmin != 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Checks if we're working via pu_stub or not + +MIR_APP_DLL(bool) PU::IsDirect() +{ + return g_hPipe == nullptr; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Checks if a process has enough rights to write into Miranda's folder + +MIR_APP_DLL(bool) PU::IsProcessElevated() +{ + bool bIsElevated = false; + DWORD dwError = ERROR_SUCCESS; + HANDLE hToken = nullptr; + + // Open the primary access token of the process with TOKEN_QUERY. + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { + dwError = GetLastError(); + goto Cleanup; + } + + // Retrieve token elevation information. + TOKEN_ELEVATION elevation; + DWORD dwSize; + if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize)) { + // When the process is run on operating systems prior to Windows + // Vista, GetTokenInformation returns FALSE with the + // ERROR_INVALID_PARAMETER error code because TokenElevation is + // not supported on those operating systems. + dwError = GetLastError(); + goto Cleanup; + } + + bIsElevated = elevation.TokenIsElevated != 0; + +Cleanup: + // Centralized cleanup for all allocated resources. + if (hToken) { + CloseHandle(hToken); + hToken = nullptr; + } + + // Throw the error if something failed in the function. + if (ERROR_SUCCESS != dwError) { + throw dwError; + } + + return bIsElevated; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Launches pu_stub.exe with elevated priviledges if needed + +MIR_APP_DLL(bool) PU::PrepareEscalation() +{ + // First try to create a file near Miranda32.exe + wchar_t szPath[MAX_PATH]; + GetModuleFileName(nullptr, szPath, _countof(szPath)); + wchar_t *ext = wcsrchr(szPath, '.'); + if (ext != nullptr) + *ext = '\0'; + wcscat(szPath, L".test"); + + HANDLE hFile = CreateFile(szPath, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile != INVALID_HANDLE_VALUE) { + // we are admins or UAC is disable, cool + CloseHandle(hFile); + DeleteFile(szPath); + return true; + } + + // Check the current process's "run as administrator" status. + if (IsRunAsAdmin()) + return true; + + // if pipe already opened? + if (g_hPipe != nullptr) + return true; + + // Elevate the process. Create a pipe for a stub first + wchar_t wzPipeName[MAX_PATH]; + mir_snwprintf(wzPipeName, L"\\\\.\\pipe\\Miranda_Pu_%d", GetCurrentProcessId()); + g_hPipe = CreateNamedPipe(wzPipeName, PIPE_ACCESS_DUPLEX, PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, nullptr); + if (g_hPipe == INVALID_HANDLE_VALUE) { + g_hPipe = nullptr; + } + else { + wchar_t cmdLine[100], *p; + GetModuleFileName(nullptr, szPath, ARRAYSIZE(szPath)); + if ((p = wcsrchr(szPath, '\\')) != nullptr) + wcscpy(p + 1, L"pu_stub.exe"); + mir_snwprintf(cmdLine, L"%d", GetCurrentProcessId()); + + // Launch a stub + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.lpVerb = L"runas"; + sei.lpFile = szPath; + sei.lpParameters = cmdLine; + sei.hwnd = nullptr; + sei.nShow = SW_NORMAL; + if (ShellExecuteEx(&sei)) { + if (g_hPipe != nullptr) + ConnectNamedPipe(g_hPipe, nullptr); + return true; + } + + DWORD dwError = GetLastError(); + if (dwError == ERROR_CANCELLED) { + // The user refused to allow privileges elevation. + // Do nothing ... + } + } + return false; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int TransactPipe(int opcode, const wchar_t *p1, const wchar_t *p2) +{ + BYTE buf[1024]; + DWORD l1 = lstrlen(p1), l2 = lstrlen(p2); + if (l1 > MAX_PATH || l2 > MAX_PATH) + return ERROR_BAD_ARGUMENTS; + + *(DWORD *)buf = opcode; + wchar_t *dst = (wchar_t *)&buf[sizeof(DWORD)]; + lstrcpy(dst, p1); + dst += l1 + 1; + if (p2) { + lstrcpy(dst, p2); + dst += l2 + 1; + } + else *dst++ = 0; + + DWORD dwBytes = 0, dwError; + if (!WriteFile(g_hPipe, buf, (DWORD)((BYTE *)dst - buf), &dwBytes, nullptr)) + return GetLastError(); + + dwError = 0; + if (!ReadFile(g_hPipe, &dwError, sizeof(DWORD), &dwBytes, nullptr)) + return GetLastError(); + if (dwBytes != sizeof(DWORD)) + return ERROR_BAD_ARGUMENTS; + + return dwError; +} + +MIR_APP_DLL(int) PU::SafeCopyFile(const wchar_t *pSrc, const wchar_t *pDst) +{ + if (g_hPipe == nullptr) + return CopyFileW(pSrc, pDst, FALSE); + + return TransactPipe(1, pSrc, pDst); +} + +MIR_APP_DLL(int) PU::SafeMoveFile(const wchar_t *pSrc, const wchar_t *pDst) +{ + if (g_hPipe == nullptr) { + if (!DeleteFileW(pDst)) { + DWORD dwError = GetLastError(); + if (dwError != ERROR_ACCESS_DENIED && dwError != ERROR_FILE_NOT_FOUND) + return dwError; + } + + if (!MoveFileW(pSrc, pDst)) { // use copy on error + switch (DWORD dwError = GetLastError()) { + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_NOT_FOUND: + return 0; // this file was included into many archives, so Miranda tries to move it again & again + + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + // use copy routine if a move operation isn't available + // for example, when files are on different disks + if (!CopyFileW(pSrc, pDst, FALSE)) + return GetLastError(); + + if (!DeleteFileW(pSrc)) + return GetLastError(); + break; + + default: + return dwError; + } + } + + return ERROR_SUCCESS; + } + + return TransactPipe(2, pSrc, pDst); +} + +MIR_APP_DLL(int) PU::SafeDeleteFile(const wchar_t *pwszFile) +{ + if (g_hPipe == nullptr) + return DeleteFile(pwszFile); + + return TransactPipe(3, pwszFile, nullptr); +} + +MIR_APP_DLL(int) PU::SafeCreateDirectory(const wchar_t *pwszFolder) +{ + if (g_hPipe == nullptr) + return CreateDirectoryTreeW(pwszFolder); + + return TransactPipe(4, pwszFolder, nullptr); +} + +MIR_APP_DLL(int) PU::SafeDeleteDirectory(const wchar_t *pwszDirName) +{ + if (g_hPipe == nullptr) + return DeleteDirectoryTreeW(pwszDirName); + + return TransactPipe(6, pwszDirName, nullptr); +} + +MIR_APP_DLL(int) PU::SafeCreateFilePath(const wchar_t *pwszFolder) +{ + if (g_hPipe == nullptr) { + CreatePathToFileW(pwszFolder); + return 0; + } + + return TransactPipe(5, pwszFolder, nullptr); +} |