diff options
author | George Hazan <george.hazan@gmail.com> | 2013-02-05 21:49:35 +0000 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2013-02-05 21:49:35 +0000 |
commit | 9c32e9a999c2a0d86133b1fca16f75fe10672136 (patch) | |
tree | 95f8b8c1fa8a3a07c4f81429f1d6bc557018ad52 /plugins/PluginUpdater/src | |
parent | e505b22562e80b830d43093758f376c858c6661d (diff) |
experimental version of PU that can handle UAC correctly
git-svn-id: http://svn.miranda-ng.org/main/trunk@3445 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/PluginUpdater/src')
-rw-r--r-- | plugins/PluginUpdater/src/Common.h | 16 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/Notifications.cpp | 301 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/PluginUpdater.cpp | 6 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/Scanner.cpp | 18 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/Utils.cpp | 263 | ||||
-rw-r--r-- | plugins/PluginUpdater/src/unzipfile.cpp | 76 |
6 files changed, 402 insertions, 278 deletions
diff --git a/plugins/PluginUpdater/src/Common.h b/plugins/PluginUpdater/src/Common.h index 3d79a36f33..5969dee2a3 100644 --- a/plugins/PluginUpdater/src/Common.h +++ b/plugins/PluginUpdater/src/Common.h @@ -116,13 +116,13 @@ using namespace std; extern HINSTANCE hInst;
-extern TCHAR tszRoot[MAX_PATH], tszDialogMsg[2048];
+extern TCHAR tszRoot[MAX_PATH], tszDialogMsg[2048], tszTempPath[MAX_PATH];
extern FILEINFO *pFileInfo;
extern HANDLE CheckThread, hPluginUpdaterFolder;
extern PlugOptions opts;
extern POPUP_OPTIONS PopupOptions;
extern aPopups PopupsList[POPUPS];
-extern HANDLE Timer;
+extern HANDLE Timer, hPipe;
extern HWND hwndDialog;
void InitPopupList();
@@ -154,6 +154,17 @@ INT_PTR CALLBACK DlgMsgPop(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); bool unzip(const TCHAR *ptszZipFile, TCHAR *ptszDestPath, TCHAR *ptszBackPath);
void strdel(TCHAR *parBuffer, int len);
+//////////////////////////////////////////////////////////
+
+BOOL IsRunAsAdmin();
+BOOL IsProcessElevated();
+
+int SafeCreateDirectory(const TCHAR *ptszDirName);
+int SafeCopyFile(const TCHAR *ptszSrc, const TCHAR *ptszDst);
+int SafeMoveFile(const TCHAR *ptszSrc, const TCHAR *ptszDst);
+int SafeDeleteFile(const TCHAR *ptszSrc);
+int SafeCreateFilePath(TCHAR *pFolder);
+
#if MIRANDA_VER < 0x0A00
#define db_free(A) DBFreeVariant(A)
@@ -212,7 +223,6 @@ __forceinline INT_PTR Options_AddPage(WPARAM wParam, OPTIONSDIALOGPAGE *odp) }
char *rtrim(char *str);
-void CreatePathToFileT(TCHAR *szFilePath);
#define NEWTSTR_ALLOCA(A) (A == NULL)?NULL:_tcscpy((TCHAR*)alloca((_tcslen(A)+1) *sizeof(TCHAR)), A)
diff --git a/plugins/PluginUpdater/src/Notifications.cpp b/plugins/PluginUpdater/src/Notifications.cpp index e9f26d170f..f631a1b8be 100644 --- a/plugins/PluginUpdater/src/Notifications.cpp +++ b/plugins/PluginUpdater/src/Notifications.cpp @@ -19,17 +19,17 @@ Boston, MA 02111-1307, USA. #include "common.h"
+HANDLE hPipe = NULL;
HWND hwndDialog = NULL;
static bool bShowDetails;
void PopupAction(HWND hWnd, BYTE action)
{
- switch (action)
- {
- case PCA_CLOSEPOPUP:
- break;
- case PCA_DONOTHING:
- return;
+ switch (action) {
+ case PCA_CLOSEPOPUP:
+ break;
+ case PCA_DONOTHING:
+ return;
}
PUDeletePopUp(hWnd);
}
@@ -205,8 +205,62 @@ INT_PTR CALLBACK DlgDownloadPop(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPar return FALSE;
}
-void DlgDownloadProc(FILEURL *pFileUrl, PopupDataText temp)
+bool PrepareEscalation()
{
+ // First try to create a file near Miranda32.exe
+ wchar_t szPath[MAX_PATH];
+ GetModuleFileName(NULL, szPath, SIZEOF(szPath));
+ TCHAR *ext = _tcsrchr(szPath, '.');
+ if (ext != NULL)
+ *ext = '\0';
+ _tcscat(szPath, _T(".test"));
+ HANDLE hFile = CreateFile(szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ 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;
+
+ // Elevate the process. Create a pipe for a stub first
+ TCHAR tszPipeName[MAX_PATH];
+ _stprintf_s(tszPipeName, MAX_PATH, _T("\\\\.\\pipe\\Miranda_Pu_%d"), GetCurrentProcessId());
+ hPipe = CreateNamedPipe(tszPipeName, PIPE_ACCESS_DUPLEX, PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
+ if (hPipe == INVALID_HANDLE_VALUE) {
+ hPipe = NULL;
+ return false;
+ }
+
+ wchar_t cmdLine[100], *p;
+ GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath));
+ if ((p = wcsrchr(szPath, '\\')) != 0)
+ wcscpy(p+1, L"pu_stub.exe");
+ mir_sntprintf(cmdLine, SIZEOF(cmdLine), L"%d", GetCurrentProcessId());
+
+ // Launch a stub
+ SHELLEXECUTEINFO sei = { sizeof(sei) };
+ sei.lpVerb = L"runas";
+ sei.lpFile = szPath;
+ sei.lpParameters = cmdLine;
+ sei.hwnd = NULL;
+ sei.nShow = SW_NORMAL;
+ if (ShellExecuteEx(&sei)) {
+ if (hPipe != NULL)
+ ConnectNamedPipe(hPipe, NULL);
+ return true;
+ }
+
+ DWORD dwError = GetLastError();
+ if (dwError == ERROR_CANCELLED)
+ {
+ // The user refused to allow privileges elevation.
+ // Do nothing ...
+ }
+ return false;
}
void SelectAll(HWND hDlg, bool bEnable)
@@ -228,15 +282,27 @@ static void SetStringText(HWND hWnd, size_t i, TCHAR *ptszText) static void ApplyUpdates(void *param)
{
HWND hDlg = (HWND)param;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // if we need to escalate priviledges, launch a atub
+
+ if ( !PrepareEscalation()) {
+ DestroyWindow(hDlg);
+ return;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // ok, let's unpack all zips
+
HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES);
OBJLIST<FILEINFO> &todo = *(OBJLIST<FILEINFO> *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
TCHAR tszBuff[2048], tszFileTemp[MAX_PATH], tszFileBack[MAX_PATH];
mir_sntprintf(tszFileBack, SIZEOF(tszFileBack), _T("%s\\Backups"), tszRoot);
- CreateDirectory(tszFileBack, NULL);
+ SafeCreateDirectory(tszFileBack);
mir_sntprintf(tszFileTemp, SIZEOF(tszFileTemp), _T("%s\\Temp"), tszRoot);
- CreateDirectory(tszFileTemp, NULL);
+ SafeCreateDirectory(tszFileTemp);
for (int i=0; i < todo.getCount(); ++i) {
ListView_EnsureVisible(hwndList, i, FALSE);
@@ -260,6 +326,9 @@ static void ApplyUpdates(void *param) }
if (todo.getCount() == 0) {
+LBL_Exit:
+ if (hPipe)
+ CloseHandle(hPipe);
DestroyWindow(hDlg);
return;
}
@@ -272,8 +341,7 @@ static void ApplyUpdates(void *param) if (rc != IDYES) {
mir_sntprintf(tszBuff, SIZEOF(tszBuff), TranslateT("You have chosen not to install the plugin updates immediately.\nYou can install it manually from this location:\n\n%s"), tszFileTemp);
ShowPopup(0, LPGENT("Plugin Updater"), tszBuff, 2, 0);
- DestroyWindow(hDlg);
- return;
+ goto LBL_Exit;
}
TCHAR *tszMirandaPath = Utils_ReplaceVarsT(_T("%miranda_path%"));
@@ -301,12 +369,12 @@ static void ApplyUpdates(void *param) }
if ( unzip(p.File.tszDiskPath, tszMirandaPath, tszFileBack))
- DeleteFile(p.File.tszDiskPath); // remove .zip after successful update
+ SafeDeleteFile(p.File.tszDiskPath); // remove .zip after successful update
}
DBWriteContactSettingByte(NULL, MODNAME, "RestartCount", 2);
- DestroyWindow(hDlg);
CallFunctionAsync(RestartMe, 0);
+ goto LBL_Exit;
}
static void ResizeVert(HWND hDlg, int yy)
@@ -317,164 +385,6 @@ static void ResizeVert(HWND hDlg, int yy) SetWindowPos(hDlg, 0, 0, 0, r.right, r.bottom, SWP_NOMOVE | SWP_NOZORDER);
}
-//
-// 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 = NULL;
-
- // 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(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
- {
- dwError = GetLastError();
- goto Cleanup;
- }
-
-Cleanup:
- // Centralized cleanup for all allocated resources.
- if (pAdministratorsGroup)
- {
- FreeSid(pAdministratorsGroup);
- pAdministratorsGroup = NULL;
- }
-
- // 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 = NULL;
-
- // 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 = NULL;
- }
-
- // Throw the error if something failed in the function.
- if (ERROR_SUCCESS != dwError)
- {
- throw dwError;
- }
-
- return fIsElevated;
-}
-
INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES);
@@ -596,61 +506,12 @@ INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam if (HIWORD( wParam ) == BN_CLICKED) {
switch(LOWORD(wParam)) {
case IDOK:
- {
EnableWindow( GetDlgItem(hDlg, IDOK), FALSE);
EnableWindow( GetDlgItem(hDlg, IDC_SELALL), FALSE);
EnableWindow( GetDlgItem(hDlg, IDC_SELNONE), FALSE);
- wchar_t szPath[MAX_PATH];
- GetModuleFileName(NULL, szPath, SIZEOF(szPath));
- TCHAR *ext = _tcsrchr(szPath, '.');
- if (ext != NULL)
- *ext = '\0';
- _tcscat(szPath, _T(".test"));
- HANDLE hFile = CreateFile(szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE)
- {
- // Check the current process's "run as administrator" status.
- // Elevate the process if it is not run as administrator.
- if (!IsRunAsAdmin())
- {
- wchar_t cmdLine[100];
- GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath));
- TCHAR *profilename = Utils_ReplaceVarsT(_T("%miranda_profilename%"));
- mir_sntprintf(cmdLine, SIZEOF(cmdLine), _T(" /restart:%d /profile=%s"), GetCurrentProcessId(), profilename);
- // Launch itself as administrator.
- SHELLEXECUTEINFO sei = { sizeof(sei) };
- sei.lpVerb = L"runas";
- sei.lpFile = szPath;
- sei.lpParameters = cmdLine;
- sei.hwnd = hDlg;
- sei.nShow = SW_NORMAL;
-
- if (!ShellExecuteEx(&sei))
- {
- DWORD dwError = GetLastError();
- if (dwError == ERROR_CANCELLED)
- {
- // The user refused to allow privileges elevation.
- // Do nothing ...
- }
- }
- else
- {
- DestroyWindow(hDlg); // Quit itself
- CallService("CloseAction", 0, 0);
- break;
- }
- }
- }
- else
- {
- CloseHandle(hFile);
- DeleteFile(szPath);
- }
mir_forkthread(ApplyUpdates, hDlg);
return TRUE;
- }
case IDC_DETAILS:
bShowDetails = !bShowDetails;
diff --git a/plugins/PluginUpdater/src/PluginUpdater.cpp b/plugins/PluginUpdater/src/PluginUpdater.cpp index abf2078f77..3ee3dabaae 100644 --- a/plugins/PluginUpdater/src/PluginUpdater.cpp +++ b/plugins/PluginUpdater/src/PluginUpdater.cpp @@ -31,7 +31,7 @@ Boston, MA 02111-1307, USA. HANDLE hPluginUpdaterFolder = NULL, hCheckUpdates = NULL, hEmptyFolder = NULL;
HINSTANCE hInst = NULL;
-TCHAR tszRoot[MAX_PATH] = {0};
+TCHAR tszRoot[MAX_PATH] = {0}, tszTempPath[MAX_PATH];
int hLangpack;
PLUGININFOEX pluginInfoEx = {
@@ -95,6 +95,10 @@ extern "C" __declspec(dllexport) int Load(void) lstrcpyn(tszRoot, tszFolder, SIZEOF(tszRoot));
}
+ DWORD dwLen = GetTempPath( SIZEOF(tszTempPath), tszTempPath);
+ if (tszTempPath[dwLen-1] == '\\')
+ tszTempPath[dwLen-1] = 0;
+
LoadOptions();
InitPopupList();
NetlibInit();
diff --git a/plugins/PluginUpdater/src/Scanner.cpp b/plugins/PluginUpdater/src/Scanner.cpp index 15b7042a29..2c3e662f71 100644 --- a/plugins/PluginUpdater/src/Scanner.cpp +++ b/plugins/PluginUpdater/src/Scanner.cpp @@ -259,9 +259,11 @@ static void CheckUpdates(void *) {
char szKey[64] = {0};
DBVARIANT dbVar = {0};
-
- if (!Exists(tszRoot))
- CreateDirectoryTreeT(tszRoot);
+
+ TCHAR tszTempPath[MAX_PATH];
+ DWORD dwLen = GetTempPath(SIZEOF(tszTempPath), tszTempPath);
+ if (tszTempPath[dwLen-1] == '\\')
+ tszTempPath[dwLen-1] = 0;
// Load files info
if (DBGetContactSettingTString(NULL, MODNAME, "UpdateURL", &dbVar)) { // URL is not set
@@ -289,21 +291,23 @@ static void CheckUpdates(void *) FILEURL pFileUrl;
mir_sntprintf(pFileUrl.tszDownloadURL, SIZEOF(pFileUrl.tszDownloadURL), _T("%s/hashes.zip"), (TCHAR*)tszBaseUrl);
- mir_sntprintf(pFileUrl.tszDiskPath, SIZEOF(pFileUrl.tszDiskPath), _T("%s\\hashes.zip"), tszRoot);
+ mir_sntprintf(pFileUrl.tszDiskPath, SIZEOF(pFileUrl.tszDiskPath), _T("%s\\hashes.zip"), tszTempPath);
if (!DownloadFile(pFileUrl.tszDownloadURL, pFileUrl.tszDiskPath)) {
ShowPopup(0, LPGENT("Plugin Updater"), LPGENT("An error occured while downloading the update."), 1, 0);
CheckThread = NULL;
return;
}
- unzip(pFileUrl.tszDiskPath, tszRoot, tszRoot);
+ unzip(pFileUrl.tszDiskPath, tszTempPath, NULL);
DeleteFile(pFileUrl.tszDiskPath);
TCHAR tszTmpIni[MAX_PATH] = {0};
- mir_sntprintf(tszTmpIni, SIZEOF(tszTmpIni), _T("%s\\hashes.txt"), tszRoot);
+ mir_sntprintf(tszTmpIni, SIZEOF(tszTmpIni), _T("%s\\hashes.txt"), tszTempPath);
FILE *fp = _tfopen(tszTmpIni, _T("r"));
- if (!fp)
+ if (!fp) {
+ CheckThread = NULL;
return;
+ }
SERVLIST hashes(50, CompareHashes);
char str[200];
diff --git a/plugins/PluginUpdater/src/Utils.cpp b/plugins/PluginUpdater/src/Utils.cpp index 7a79dd3a10..1946babfca 100644 --- a/plugins/PluginUpdater/src/Utils.cpp +++ b/plugins/PluginUpdater/src/Utils.cpp @@ -124,7 +124,6 @@ void LoadOptions() BOOL DownloadFile(LPCTSTR tszURL, LPCTSTR tszLocal)
{
- HANDLE hFile = NULL;
DWORD dwBytes;
NETLIBHTTPREQUEST nlhr = {0};
@@ -152,9 +151,25 @@ BOOL DownloadFile(LPCTSTR tszURL, LPCTSTR tszLocal) NETLIBHTTPREQUEST *pReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hNetlibUser,(LPARAM)&nlhr);
if (pReply) {
if ((200 == pReply->resultCode) && (pReply->dataLength > 0)) {
- hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, NULL);
- ret = true;
+ HANDLE hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile != INVALID_HANDLE_VALUE) {
+ // write the downloaded file firectly
+ WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, NULL);
+ CloseHandle(hFile);
+ ret = true;
+ }
+ else {
+ // try to write it via PU stub
+ TCHAR tszTempFile[MAX_PATH];
+ mir_sntprintf(tszTempFile, SIZEOF(tszTempFile), _T("%s\\pulocal.tmp"), tszTempPath);
+ hFile = CreateFile(tszTempFile, GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile != INVALID_HANDLE_VALUE) {
+ WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, NULL);
+ CloseHandle(hFile);
+ SafeMoveFile(tszTempFile, tszLocal);
+ ret = true;
+ }
+ }
}
CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)pReply);
}
@@ -162,8 +177,6 @@ BOOL DownloadFile(LPCTSTR tszURL, LPCTSTR tszLocal) mir_free(szUrl);
mir_free(nlhr.headers);
- if (hFile)
- CloseHandle(hFile);
DlgDld = ret;
return ret;
}
@@ -253,15 +266,237 @@ char* rtrim(char *str) }
return str;
}
+#endif
-void CreatePathToFileT(TCHAR *szFilePath)
+// 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()
{
- TCHAR *pszLastBackslash = _tcsrchr(szFilePath, '\\');
- if (pszLastBackslash == NULL)
- return;
+ BOOL fIsRunAsAdmin = FALSE;
+ DWORD dwError = ERROR_SUCCESS;
+ PSID pAdministratorsGroup = NULL;
+
+ // 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(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
+ {
+ dwError = GetLastError();
+ goto Cleanup;
+ }
- *pszLastBackslash = '\0';
- CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)szFilePath);
- *pszLastBackslash = '\\';
+Cleanup:
+ // Centralized cleanup for all allocated resources.
+ if (pAdministratorsGroup)
+ {
+ FreeSid(pAdministratorsGroup);
+ pAdministratorsGroup = NULL;
+ }
+
+ // 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 = NULL;
+
+ // 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 = NULL;
+ }
+
+ // Throw the error if something failed in the function.
+ if (ERROR_SUCCESS != dwError)
+ {
+ throw dwError;
+ }
+
+ return fIsElevated;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int TransactPipe(int opcode, const TCHAR *p1, const TCHAR *p2)
+{
+ BYTE buf[1024];
+ DWORD l1 = lstrlen(p1), l2 = lstrlen(p2);
+ if (l1 > MAX_PATH || l2 > MAX_PATH)
+ return 0;
+
+ *(DWORD*)buf = opcode;
+ TCHAR *dst = (TCHAR*)&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(hPipe, buf, (DWORD)((BYTE*)dst - buf), &dwBytes, NULL) == 0)
+ return 0;
+
+ dwError = 0;
+ if ( ReadFile(hPipe, &dwError, sizeof(DWORD), &dwBytes, NULL) == 0) return 0;
+ if (dwBytes != sizeof(DWORD)) return 0;
+
+ return dwError == ERROR_SUCCESS;
+}
+
+int SafeCopyFile(const TCHAR *pSrc, const TCHAR *pDst)
+{
+ if (hPipe == NULL)
+ return CopyFile(pSrc, pDst, FALSE);
+
+ return TransactPipe(1, pSrc, pDst);
+}
+
+int SafeMoveFile(const TCHAR *pSrc, const TCHAR *pDst)
+{
+ if (hPipe == NULL) {
+ DeleteFile(pDst);
+ if ( MoveFile(pSrc, pDst) == 0) // use copy on error
+ CopyFile(pSrc, pDst, FALSE);
+ DeleteFile(pSrc);
+ }
+
+ return TransactPipe(2, pSrc, pDst);
+}
+
+int SafeDeleteFile(const TCHAR *pFile)
+{
+ if (hPipe == NULL)
+ return DeleteFile(pFile);
+
+ return TransactPipe(3, pFile, NULL);
+}
+
+int SafeCreateDirectory(const TCHAR *pFolder)
+{
+ if (hPipe == NULL)
+ return CreateDirectoryTreeT(pFolder);
+
+ return TransactPipe(4, pFolder, NULL);
+}
+
+int SafeCreateFilePath(TCHAR *pFolder)
+{
+ if (hPipe == NULL) {
+ CreatePathToFileT(pFolder);
+ return 0;
+ }
+
+ return TransactPipe(5, pFolder, NULL);
}
-#endif
diff --git a/plugins/PluginUpdater/src/unzipfile.cpp b/plugins/PluginUpdater/src/unzipfile.cpp index b2b621d37a..2362debf44 100644 --- a/plugins/PluginUpdater/src/unzipfile.cpp +++ b/plugins/PluginUpdater/src/unzipfile.cpp @@ -37,12 +37,8 @@ static void PrepareFileName(TCHAR *dest, size_t destSize, const TCHAR *ptszPath, void BackupFile(TCHAR *ptszSrcFileName, TCHAR *ptszBackFileName)
{
- CreatePathToFileT(ptszBackFileName);
- DeleteFile(ptszBackFileName);
- if ( MoveFile(ptszSrcFileName, ptszBackFileName) == 0) { // use copy on error
- CopyFile(ptszSrcFileName, ptszBackFileName, FALSE);
- DeleteFile(ptszSrcFileName);
- }
+ SafeCreateFilePath(ptszBackFileName);
+ SafeMoveFile(ptszSrcFileName, ptszBackFileName);
}
bool extractCurrentFile(unzFile uf, TCHAR *ptszDestPath, TCHAR *ptszBackPath)
@@ -69,38 +65,52 @@ bool extractCurrentFile(unzFile uf, TCHAR *ptszDestPath, TCHAR *ptszBackPath) if (err != UNZ_OK)
return false;
- PrepareFileName(tszDestFile, SIZEOF(tszDestFile), ptszDestPath, ptszNewName);
- PrepareFileName(tszBackFile, SIZEOF(tszBackFile), ptszBackPath, ptszNewName);
- BackupFile(tszDestFile, tszBackFile);
+ if (ptszBackPath != NULL) {
+ PrepareFileName(tszDestFile, SIZEOF(tszDestFile), ptszDestPath, ptszNewName);
+ PrepareFileName(tszBackFile, SIZEOF(tszBackFile), ptszBackPath, ptszNewName);
+ BackupFile(tszDestFile, tszBackFile);
+ }
PrepareFileName(tszDestFile, SIZEOF(tszDestFile), ptszDestPath, ptszNewName);
- CreatePathToFileT(tszDestFile);
-
- HANDLE hFile = CreateFile(tszDestFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0,
- CREATE_ALWAYS, file_info.external_fa, 0);
-
- if (hFile != INVALID_HANDLE_VALUE) {
- while (true) {
- err = unzReadCurrentFile(uf, buf, sizeof(buf));
- if (err <= 0)
- break;
-
- DWORD bytes;
- if (!WriteFile(hFile, buf, err, &bytes, FALSE)) {
- err = UNZ_ERRNO;
- break;
- }
+ SafeCreateFilePath(tszDestFile);
+
+ TCHAR *ptszFile2unzip;
+ if (hPipe == NULL) // direct mode
+ ptszFile2unzip = tszDestFile;
+ else {
+ TCHAR tszTempPath[MAX_PATH];
+ GetTempPath( SIZEOF(tszTempPath), tszTempPath);
+ GetTempFileName(tszTempPath, _T("PUtemp"), GetCurrentProcessId(), tszBackFile);
+ ptszFile2unzip = tszBackFile;
+ }
+
+ HANDLE hFile = CreateFile(ptszFile2unzip, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, file_info.external_fa, 0);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return false;
+
+ while (true) {
+ err = unzReadCurrentFile(uf, buf, sizeof(buf));
+ if (err <= 0)
+ break;
+
+ DWORD bytes;
+ if (!WriteFile(hFile, buf, err, &bytes, FALSE)) {
+ err = UNZ_ERRNO;
+ break;
}
+ }
- FILETIME ftLocal, ftCreate, ftLastAcc, ftLastWrite;
- GetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite);
- DosDateTimeToFileTime(HIWORD(file_info.dosDate), LOWORD(file_info.dosDate), &ftLocal);
- LocalFileTimeToFileTime(&ftLocal, &ftLastWrite);
- SetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite);
+ FILETIME ftLocal, ftCreate, ftLastAcc, ftLastWrite;
+ GetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite);
+ DosDateTimeToFileTime(HIWORD(file_info.dosDate), LOWORD(file_info.dosDate), &ftLocal);
+ LocalFileTimeToFileTime(&ftLocal, &ftLastWrite);
+ SetFileTime(hFile, &ftCreate, &ftLastAcc, &ftLastWrite);
- CloseHandle(hFile);
- unzCloseCurrentFile(uf); /* don't lose the error */
- }
+ CloseHandle(hFile);
+ unzCloseCurrentFile(uf); /* don't lose the error */
+
+ if (hPipe)
+ SafeMoveFile(ptszFile2unzip, tszDestFile);
}
mir_free(ptszNewName);
return true;
|