summaryrefslogtreecommitdiff
path: root/src/mir_app
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2020-10-29 19:21:32 +0300
committerGeorge Hazan <ghazan@miranda.im>2020-10-29 19:21:32 +0300
commit74e691804c25c6174cb619d21b19fb5dc94afa22 (patch)
tree98625fbff7a1c7da877f208e13d0e49962ddffa1 /src/mir_app
parent21aaad51c5e0bcf7157bd8e37e6e8ee0d1e55525 (diff)
Plugin Updater: pu_stub utilities moved to mir_app
Diffstat (limited to 'src/mir_app')
-rw-r--r--src/mir_app/mir_app.vcxproj1
-rw-r--r--src/mir_app/mir_app.vcxproj.filters3
-rw-r--r--src/mir_app/src/mir_app.def9
-rw-r--r--src/mir_app/src/mir_app64.def9
-rw-r--r--src/mir_app/src/pu_utils.cpp296
5 files changed, 318 insertions, 0 deletions
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);
+}