diff --git a/admin/win/RELEASE_NOTES.txt b/admin/win/RELEASE_NOTES.txt new file mode 100755 index 000000000..fd3e8f620 --- /dev/null +++ b/admin/win/RELEASE_NOTES.txt @@ -0,0 +1 @@ +TO DO \ No newline at end of file diff --git a/admin/win/installer.ico b/admin/win/installer.ico new file mode 100755 index 000000000..94753ac29 Binary files /dev/null and b/admin/win/installer.ico differ diff --git a/admin/win/nsis_uac/History.txt b/admin/win/nsis_uac/History.txt new file mode 100755 index 000000000..ee8af46c0 --- /dev/null +++ b/admin/win/nsis_uac/History.txt @@ -0,0 +1,102 @@ +History: +-------- + +v0.0.11d - 20090705 (AndersK) + *Fixed UAC_RealWorldFullyLoadedDualModeExample.nsi so installing as admin will allow both modes + +v0.0.11c - 20090124 (AndersK) + *Checks for seclogon service on NT5 and returns ERROR_SERVICE_NOT_ACTIVE in $0 if not running + +v0.0.11b - 20090102 (AndersK) + *Fixed unicode compile bugs + +v0.0.11 - 20081021 (AndersK) + +Added UAC_GetUserShellFolderPath.nsi (Uses the new UAC::GetShellFolderPath) + +v0.0.10a - 20081004 (AndersK) + +Added SEE_MASK_NOZONECHECKS flag (experimental) + +v0.0.10 - 20080812 (AndersK) + +Added ugly hook hack to the shells run-as dialog on xp, defaults to other user + +v0.0.9 - 20080721 (AndersK) + *Fixed UAC_RealWorldFullyLoadedDualModeExample.nsi related bug (Thanks Case) + +v0.0.8 - 20080310 (AndersK) + +HTML Readme + +Added UAC::GetOuterHwnd (used by UAC_RealWorldFullyLoadedDualModeExample.nsi) + *Fixed UAC_RealWorldFullyLoadedDualModeExample.nsi + *Major code cleanup in UAC.cpp + -Removed UAC::RunElevatedAndProcessMessages (UAC::RunElevated now supports non NULL $HWNDParent) + -Removed several useless sample scripts + +v0.0.7e - 20080229 (AndersK) + *Added ugly hack for hackwnd to find correct title and give us a proper taskbar so the elevation dialog does not get lost (2000,XP (This also fixed Alt-Tab icon on Vista)) + *Should compile with MSVC2005 now (Thanks Case) + *More unicode fixes, this time even tested with NSIS Unicode (Only RunElevated and Exec tested) + +v0.0.7d - 20080226 (AndersK) + *Fixed a couple of unicode version bugs (Unicode version still untested) + *Fixed weird XP string length bug (Thanks kfank) + +v0.0.7c - 20080218 (AndersK) + *Fixed SyncVars string length bug + +v0.0.7b - 20080205 (AndersK) + *Fixed DelayLoadDlls() problem on NT4 + +v0.0.7 - 20080120 (AndersK) + +Added UAC::StackPush (For use with ExecCodeSegment) + +v0.0.6d - 20071108 (AndersK) + +Now syncs basic registers/variables before calling UAC::*Exec* and UAC::ExecCodeSegment (r0-r9,R0-R9,$CMDLINE,$INSTDIR,$OUTDIR,$EXEDIR,$LANGUAGE) + +Added UAC::RunElevatedAndProcessMessages, this can be called after .onInit (Very experimental, DO NOT USE) + +New include file with helper macros: UAC.nsh + *Replazed Clammerz hack with a better version + +v0.0.6c - 20071014 (AndersK) + +Check for and split up "domain\user" style input in RunAs.cpp for CreateProcessWithLogonW + *Added a ugly hack to trick messagebox'es in .OnInit to appear correctly on Vista (Thanks Clammerz) + +v0.0.6b - 20070523 (AndersK) + *Fixed showwindow flag (Thanks for the help kichik) + +v0.0.6 - 20070512 (AndersK) + +Added basic language support for MyRunAs dialog. + +v0.0.5e - 20070509 (AndersK) + *Fixed detection of UAC mode? + +IPC window is visible (but offscreen) during elevation to help with SetForegroundWindow/Focus problems + +v0.0.5d - 20070324 (AndersK) + *Fixed stupid IsAdmin bug + +v0.0.5c - 20070304 (AndersK) + *_IsAdmin now uses CheckTokenMembership if it exists ( MSKB:Q118626 / http://blogs.msdn.com/larryosterman/archive/2007/03/14/why-does-kb-118626-use-accesscheck-to-check-if-you-re-a-member-of-the-administrators-group.aspx ) + +v0.0.5b - 20070301 (AndersK) + *Fixed ExecCodeSegment (Thread now calls CoInitialize) + +v0.0.5 - 20070228 (AndersK) + +Added ExecCodeSegment (You can now call ANY code in the context of the original user) + +v0.0.4b - 20070226 (AndersK) + *Fixed (My)RunAs font (http://blogs.msdn.com/oldnewthing/archive/2005/02/04/366987.aspx) + +v0.0.4 - 20070225 (AndersK) + +Added (My)RunAs dialog, used on Vista when running as LUA with UAC off + +Always uses /NCRC for elevated instance + *Now compiles as UNICODE (Untested, no UnicodeNSIS to test on) + +v0.0.3 - 20070224 (AndersK) + +Added Exec/ExecWait + +Added Verb & ShowWindow support for ShellExec[Wait] + +v0.0.2 - 20070219 (AndersK) + +Added ShellExecWait + *IPC srv wnd now has its own thread and msg loop + *Removed CRT dependency + *Hopefully loads on Win95 now + +v0.0.1 - 20070215 (AndersK) + *Initial release \ No newline at end of file diff --git a/admin/win/nsis_uac/License.txt b/admin/win/nsis_uac/License.txt new file mode 100755 index 000000000..a83294f8a --- /dev/null +++ b/admin/win/nsis_uac/License.txt @@ -0,0 +1,14 @@ +This software is provided 'as-is', without any express or implied warranty. + +ZLIB/LIBPNG LICENSE +------------------- + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. \ No newline at end of file diff --git a/admin/win/nsis_uac/NSISUtil.h b/admin/win/nsis_uac/NSISUtil.h new file mode 100755 index 000000000..d9920c375 --- /dev/null +++ b/admin/win/nsis_uac/NSISUtil.h @@ -0,0 +1,149 @@ +/* +Alternative to ExDll.h + +v0.0.1 - 20060811 (AndersK) +*/ + +#pragma once +#include + + +typedef TCHAR NSISCH; +#define NSISCALL __stdcall + +namespace NSIS { + +__forceinline void* NSISCALL MemAlloc(SIZE_T cb) {return GlobalAlloc(LPTR,cb);} +__forceinline void NSISCALL MemFree(void* p) {GlobalFree(p);} + +enum { +INST_0, // $0 +INST_1, // $1 +INST_2, // $2 +INST_3, // $3 +INST_4, // $4 +INST_5, // $5 +INST_6, // $6 +INST_7, // $7 +INST_8, // $8 +INST_9, // $9 +INST_R0, // $R0 +INST_R1, // $R1 +INST_R2, // $R2 +INST_R3, // $R3 +INST_R4, // $R4 +INST_R5, // $R5 +INST_R6, // $R6 +INST_R7, // $R7 +INST_R8, // $R8 +INST_R9, // $R9 +INST_CMDLINE, // $CMDLINE +INST_INSTDIR, // $INSTDIR +INST_OUTDIR, // $OUTDIR +INST_EXEDIR, // $EXEDIR +INST_LANG, // $LANGUAGE +__INST_LAST, + +VIDX_TEMP=(INST_LANG+1), //#define state_temp_dir g_usrvars[25] +VIDX_PLUGINSDIR,//# define state_plugins_dir g_usrvars[26] +VIDX_EXEPATH,//#define state_exe_path g_usrvars[27] +VIDX_EXEFILENAME,//#define state_exe_file g_usrvars[28] +VIDX_STATECLICKNEXT,//#define state_click_next g_usrvars[30] +__VIDX_UNDOCLAST +}; + + + +typedef struct _stack_t { + struct _stack_t *next; + NSISCH text[ANYSIZE_ARRAY]; +} stack_t; + +typedef struct { + int autoclose; + int all_user_var; + int exec_error; + int abort; + int exec_reboot; + int reboot_called; + int XXX_cur_insttype; // deprecated + int XXX_insttype_changed; // deprecated + int silent; + int instdir_error; + int rtl; + int errlvl; +//NSIS v2.3x ? + int alter_reg_view; + int status_update; +} exec_flags_type; + +typedef struct { + exec_flags_type *exec_flags; + int (NSISCALL *ExecuteCodeSegment)(int, HWND); + void (NSISCALL *validate_filename)(char *); +} extra_parameters; + +extern UINT StrSize; +extern stack_t **StackTop; +extern NSISCH*Vars; + +inline bool NSISCALL SetErrLvl(extra_parameters*pExtraParams,int ErrLevel) {return pExtraParams? ((pExtraParams->exec_flags->errlvl=ErrLevel)||true):false;} +inline bool NSISCALL SetErrorFlag(extra_parameters*pExtraParams) {return pExtraParams? ((pExtraParams->exec_flags->exec_error=1)||true):false;} +inline bool NSISCALL ClearErrorFlag(extra_parameters*pExtraParams) {return pExtraParams?((pExtraParams->exec_flags->exec_error=0)||true):false;} + +__forceinline int NSISCALL ExecuteCodeSegment(extra_parameters*pExtraParams,int pos,HWND hwndProgress=NULL) { + return pExtraParams?pExtraParams->ExecuteCodeSegment(pos,hwndProgress):(/*EXEC_ERROR*/0x7FFFFFFF); +} + +static NSISCH* __fastcall GetVar(const int varnum) +{ + //ASSERT(NSIS::Vars && NSIS::StrSize); + if (varnum < 0 || varnum >= __VIDX_UNDOCLAST) return NULL; + return NSIS::Vars+(varnum*NSIS::StrSize); +} + +inline void NSISCALL SetVarUINT(const int varnum,UINT Value) { + wsprintf(GetVar(varnum),_T("%u"),Value); +} + +static stack_t* NSISCALL StackPop() { + if (NSIS::StackTop && *NSIS::StackTop) { + stack_t*s=(*NSIS::StackTop); + *NSIS::StackTop=(*NSIS::StackTop)->next; + return s; + } + return 0; +} +__forceinline void NSISCALL StackFreeItem(stack_t*pStackItem) {NSIS::MemFree(pStackItem);} + +static DWORD NSISCALL StackPush(NSISCH*InStr,UINT StackStrSize=NSIS::StrSize) { + if (!NSIS::StackTop)return ERROR_INVALID_PARAMETER; + stack_t*sNew=(stack_t*)NSIS::MemAlloc(sizeof(stack_t)+(StackStrSize*sizeof(NSISCH))); + if (!sNew)return ERROR_OUTOFMEMORY; + lstrcpyn(sNew->text,InStr,StackStrSize); + sNew->next=*NSIS::StackTop; + *NSIS::StackTop=sNew; + return NO_ERROR; +} + +}; /* namespace */ + +#define NSISUTIL_INIT() namespace NSIS {static UINT StrSize;static stack_t **StackTop;static NSISCH*Vars;}//Call in only ONE source file +#define NSISUTIL_INITEXPORT(_v,_strsize,_stackt) NSIS::Vars=_v;NSIS::StrSize=_strsize;NSIS::StackTop=_stackt + +//#define NSISEXPORT4(_func,_h,_strsize,_v,_stackt) extern "C" void __declspec(dllexport) __cdecl \ +// _func (HWND _h,int _strsize,NSISCH*_v,NSIS::stack_t **_stackt) { NSISUTIL_INITEXPORT(_v,_strsize,_stackt); TRACE("EXPORT::" #_func "\n"); +//#define NSISEXPORT5(_func,_h,_strsize,_v,_stackt,_eparams) extern "C" void __declspec(dllexport) __cdecl \ +// _func (HWND _h,int _strsize,NSISCH*_v,NSIS::stack_t **_stackt,NSIS::extra_parameters* _eparams) { NSISUTIL_INITEXPORT(_v,_strsize,_stackt); TRACE("EXPORT::" #_func "\n"); +//#define NSISEXPORT NSISEXPORT5 + +#ifdef _MSC_VER +# define EXPORTNSISFUNC extern "C" void __declspec(dllexport) __cdecl +# else +# error EXPORTNSISFUNC needs compiler goo, you are on your own! +# endif +#define NSISFUNCSTART4(_h,_strsize,_v,_stackt) {NSISUTIL_INITEXPORT(_v,_strsize,_stackt); +#define NSISFUNCSTART5(_h,_strsize,_v,_stackt,_eparams) NSISFUNCSTART4(_h,_strsize,_v,_stackt) +#define NSISFUNCSTART NSISFUNCSTART5 +#define NSISFUNCEND() } + diff --git a/admin/win/nsis_uac/Release/A/UAC.dll b/admin/win/nsis_uac/Release/A/UAC.dll new file mode 100755 index 000000000..edf21305a Binary files /dev/null and b/admin/win/nsis_uac/Release/A/UAC.dll differ diff --git a/admin/win/nsis_uac/Release/U/UAC.dll b/admin/win/nsis_uac/Release/U/UAC.dll new file mode 100755 index 000000000..94dc71154 Binary files /dev/null and b/admin/win/nsis_uac/Release/U/UAC.dll differ diff --git a/admin/win/nsis_uac/RunAs.cpp b/admin/win/nsis_uac/RunAs.cpp new file mode 100755 index 000000000..6d74b95a9 --- /dev/null +++ b/admin/win/nsis_uac/RunAs.cpp @@ -0,0 +1,277 @@ +//Copyright (C) 2007 Anders Kjersem. Licensed under the zlib/libpng license, see License.txt for details. +/* +If UAC is disabled, the runas verb is broken (Vista RTM) so when running as LUA there is no way to elevate so +we provide our own dialog. +*/ + +#include "UAC.h" +#ifdef FEAT_CUSTOMRUNASDLG +#include //UNLEN && GNLEN && PWLEN +#include +#include "resource.h" +#include "NSISUtil.h" +using namespace NSIS; +#define ERRAPP_TRYAGAIN (0x20000000|1) +#define MYMAX_DOMAIN (2+max(GNLEN,MAX_COMPUTERNAME_LENGTH)+1) + + +static LPCTSTR g_RunAsDlgTitle=_T("Run as"); +static LPCTSTR g_RunAsHelpText=_T("You may not have the necessary permissions to use all the features of the program you are about to run. You may run this program as a different user or continue to run the program as the current user."); +static LPCTSTR g_RunAsCurrUsrFmt=_T("&Current user (%s)");//Max 50 chars! +static LPCTSTR g_RunAsSpecHelp=_T("Run the program as the &following user:"); + +FORCEINLINE bool MySetDlgItemText(HWND hDlg,int id,LPCTSTR s) {return MySndDlgItemMsg(hDlg,id,WM_SETTEXT,0,(LPARAM)s)!=0;} + +typedef struct { + SHELLEXECUTEINFO*pSEI; + bool AsSelf; +} RUNASDLGDATA; + +void MyRunAsFmtCurrUserRadio(HWND hDlg,LPCTSTR Fmt) { + TCHAR bufFullName[MYMAX_DOMAIN+UNLEN+1]; + TCHAR buf[50+MYMAX_DOMAIN+UNLEN+1]; + *bufFullName=0; + ULONG cch; + if ((!_GetUserNameEx || !_GetUserNameEx(NameSamCompatible,bufFullName,&(cch=COUNTOF(bufFullName)))) && + !_GetUserName(bufFullName,&(cch=COUNTOF(bufFullName))) ) { + *bufFullName=0; + } + wsprintf(buf,Fmt,*bufFullName?bufFullName:_T("?")); + MySetDlgItemText(hDlg,IDC_RUNASCURR,buf); + + // default the "User name:" to Administrator from shell32 + if (LoadString(GetModuleHandle(_T("SHELL32.dll")),21763, bufFullName, COUNTOF(bufFullName)) > 0) { + MySetDlgItemText(hDlg,IDC_USERNAME,bufFullName); + } +} + +#ifdef FEAT_CUSTOMRUNASDLG_TRANSLATE +void MyRunAsTranslateDlgString(LPCTSTR StrID,LPTSTR Ini,HWND hDlg,INT_PTR DlgItemId,int special=0) { + TCHAR buf[MAX_PATH*2]; + DWORD len=GetPrivateProfileString(_T("MyRunAsStrings"),StrID,0,buf,ARRAYSIZE(buf),Ini); + if (len) { + if (IDC_RUNASCURR==special) + MyRunAsFmtCurrUserRadio(hDlg,buf); + else + (DlgItemId==-1) ? SetWindowText(hDlg,buf) : MySetDlgItemText(hDlg,DlgItemId,buf); + } +} + +void MyRunAsTranslateDlg(HWND hDlg) { + DWORD len; + TCHAR buf[MAX_PATH*2]; + HMODULE hDll=GetWindowInstance(hDlg);ASSERT(hDll); + if ( (len=GetModuleFileName(hDll,buf,ARRAYSIZE(buf))) <1)return; + buf[len-3]=0; + lstrcat(buf,_T("lng")); + MyRunAsTranslateDlgString(_T("DlgTitle"),buf,hDlg,-1); + MyRunAsTranslateDlgString(_T("HelpText"),buf,hDlg,IDC_HELPTEXT); + MyRunAsTranslateDlgString(_T("OptCurrUser"),buf,hDlg,IDC_RUNASCURR,IDC_RUNASCURR); + MyRunAsTranslateDlgString(_T("OptOtherUser"),buf,hDlg,IDC_RUNASSPEC); + MyRunAsTranslateDlgString(_T("Username"),buf,hDlg,IDC_LBLUSER); + MyRunAsTranslateDlgString(_T("Pwd"),buf,hDlg,IDC_LBLPWD); + MyRunAsTranslateDlgString(_T("OK"),buf,hDlg,IDOK); + MyRunAsTranslateDlgString(_T("Cancel"),buf,hDlg,IDCANCEL); + HWND h=GetDlgItem(hDlg,IDC_RUNASCURR); + if (GetPrivateProfileInt(_T("MyRunAsCfg"),_T("DisableCurrUserOpt"),false,buf))EnableWindow(h,false); + if (GetPrivateProfileInt(_T("MyRunAsCfg"),_T("HideCurrUserOpt"),false,buf))ShowWindow(h,false); +} +#endif + +bool ErrorIsLogonError(DWORD err) { + switch (err) { + case ERROR_LOGON_FAILURE: + case ERROR_ACCOUNT_RESTRICTION: + case ERROR_INVALID_LOGON_HOURS: + case ERROR_INVALID_WORKSTATION: + case ERROR_PASSWORD_EXPIRED: + case ERROR_ACCOUNT_DISABLED: + case ERROR_NONE_MAPPED: + case ERROR_NO_SUCH_USER: + case ERROR_INVALID_ACCOUNT_NAME: + return true; + } + return false; +} + + + +void VerifyOKBtn(HWND hDlg,RUNASDLGDATA*pRADD) { + const bool HasText=pRADD?(pRADD->AsSelf?true:MySndDlgItemMsg(hDlg,IDC_USERNAME,WM_GETTEXTLENGTH)>0):false; + EnableWindow(GetDlgItem(hDlg,IDOK),HasText); +} + +void SetDlgState(HWND hDlg,bool AsSelf,RUNASDLGDATA*pRADD) { + if (pRADD)pRADD->AsSelf=AsSelf; + MySndDlgItemMsg(hDlg,IDC_RUNASCURR,BM_SETCHECK,AsSelf?BST_CHECKED:BST_UNCHECKED); + MySndDlgItemMsg(hDlg,IDC_RUNASSPEC,BM_SETCHECK,!AsSelf?BST_CHECKED:BST_UNCHECKED); + int ids[]={IDC_USERNAME,IDC_PASSWORD,IDC_LBLUSER,IDC_LBLPWD}; + for (int i=0; ipSEI; + PROCESS_INFORMATION pi={0}; + DWORD ec=NO_ERROR; + WCHAR*wszExec;//Also used as TCHAR buffer in AsSelf mode + bool PerformTCharFmt=pRADD->AsSelf; + //const DWORD CommonStartupInfoFlags=STARTF_FORCEONFEEDBACK; +#ifdef UNICODE + PerformTCharFmt=true; +#endif + wszExec=(WCHAR*)NSIS::MemAlloc( (pRADD->AsSelf?sizeof(TCHAR):sizeof(WCHAR)) *(lstrlen(sei.lpFile)+1+lstrlen(sei.lpParameters)+1)); + if (!wszExec)ec=ERROR_OUTOFMEMORY; + if (PerformTCharFmt)wsprintf((TCHAR*)wszExec,_T("%s%s%s"),sei.lpFile,((sei.lpParameters&&*sei.lpParameters)?_T(" "):_T("")),sei.lpParameters); + if (!ec) { + if (pRADD->AsSelf) { + STARTUPINFO si={sizeof(si)}; + TRACEF("MyRunAs:CreateProcess:%s|\n",wszExec); + ec=(CreateProcess(0,(TCHAR*)wszExec,0,0,false,0,0,0,&si,&pi)?NO_ERROR:GetLastError()); + } + else { + //All Wide strings! + WCHAR wszPwd[PWLEN+1]; + WCHAR wszUName[UNLEN+1+MYMAX_DOMAIN+1]; + STARTUPINFOW siw={sizeof(siw)}; + WCHAR*p; +#ifndef UNICODE + //Build unicode string, we already know the buffer is big enough so no error handling + p=wszExec; + MultiByteToWideChar(CP_THREAD_ACP,0,sei.lpFile,-1,p,0xFFFFFF); + if (sei.lpParameters && *sei.lpParameters) { + p+=lstrlen(sei.lpFile);*p++=L' ';*p=0; + MultiByteToWideChar(CP_THREAD_ACP,0,sei.lpParameters,-1,p,0xFFFFFF); + } +#endif + SendMessageW(GetDlgItem(hwnd,IDC_USERNAME),WM_GETTEXT,COUNTOF(wszUName),(LPARAM)wszUName); + SendMessageW(GetDlgItem(hwnd,IDC_PASSWORD),WM_GETTEXT,COUNTOF(wszPwd),(LPARAM)wszPwd); + + //Try to find [\\]domain\user and split into username and domain strings + WCHAR*pUName=wszUName,*pDomain=0; + p=wszUName; + //if (*p==p[1]=='\\')pUName=(p+=2);else \ //Should we still split things up if the string starts with \\ ? Is it possible to use \\machine\user at all? + ++p;//Don't parse "\something", require at least one char before backslash "?[*\]something" + while(*p && *p!='\\')++p; + if (*p=='\\') { + pDomain=pUName; + pUName=p+1;*p=0; + } + + TRACEF("MyRunAs:CreateProcessWithLogonW:%ws|%ws|%ws|%ws|\n",pUName,pDomain?pDomain:L"NO?DOMAIN",wszPwd,wszExec); + ec=(_CreateProcessWithLogonW(pUName,pDomain?pDomain:0,wszPwd,LOGON_WITH_PROFILE,0,wszExec,0,0,0,&siw,&pi)?NO_ERROR:GetLastError()); + TRACEF("MyRunAs:CreateProcessWithLogonW: ret=%u\n",ec); + SecureZeroMemory(wszPwd,sizeof(wszPwd));//if (wszPwd) {volatile WCHAR*_p=wszPwd;for(;_p&&*_p;++_p)*_p=1;if (_p)*wszPwd=0;}//Burn password (And attempt to prevent compiler from removing it) + if (ec && ErrorIsLogonError(ec)) { + LPTSTR szMsg; + DWORD ret=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,0,ec,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&szMsg,0,0); + if (ret) { + ec=ERRAPP_TRYAGAIN; + MessageBox(hwnd,szMsg,0,MB_ICONWARNING); + LocalFree(szMsg); + } + else ec=GetLastError(); + } + } + } + NSIS::MemFree(wszExec); + if (pi.hThread)CloseHandle(pi.hThread); + if (ERRAPP_TRYAGAIN==ec)break; + if (ec) { + SetLastError(ec); + exitcode=-1; + } + else { + pRADD->pSEI->hProcess=pi.hProcess; + exitcode=IDOK; + } + } + case IDCANCEL: + EndDialog(hwnd,exitcode); + } + } + break; + } + return FALSE; +} + +DWORD MyRunAs(HINSTANCE hInstDll,SHELLEXECUTEINFO&sei) { + INT_PTR ec; + ASSERT(sei.cbSize>=sizeof(SHELLEXECUTEINFO) && hInstDll); + if (ec=DelayLoadDlls())return ec; + ASSERT(_CreateProcessWithLogonW && _GetUserName); + RUNASDLGDATA radd={0}; + radd.pSEI=&sei; + ec=DialogBoxParam(hInstDll,MAKEINTRESOURCE(IDD_MYRUNAS),sei.hwnd,MyRunAsDlgProc,(LPARAM)&radd); + TRACEF("MyRunAs returned %d (%s|%s)\n",ec,sei.lpFile,sei.lpParameters); + switch(ec) { + case 0: + return ERROR_INVALID_HANDLE;//DialogBoxParam returns 0 on bad hwnd + case IDOK: + return NO_ERROR; + case IDCANCEL: + return ERROR_CANCELLED; + } + //TODO:BUGBUG: on vista, the last error seems to get lost, should probably put it in RUNASDLGDATA and always return IDOK + return GetLastError(); +} + + +#ifdef BUILD_DBG +// RunDll exports are __stdcall, we dont care about that for this debug export, rundll32.exe is able to handle this mistake +extern "C" void __declspec(dllexport) __cdecl DBGRDMyRunAs(HWND hwnd,HINSTANCE hinst,LPTSTR lpCmdLine,int nCmdShow) { + SHELLEXECUTEINFO sei={sizeof(sei)}; + sei.lpFile=_T("Notepad.exe");//sei.lpParameters=_T("param1"); + TRACEF("ec=%d\n",MyRunAs(GetModuleHandle(_T("UAC.dll")),sei)); +} +#endif + +#endif /* FEAT_CUSTOMRUNASDLG */ + diff --git a/admin/win/nsis_uac/UAC Readme.html b/admin/win/nsis_uac/UAC Readme.html new file mode 100755 index 000000000..1c8d9ed26 --- /dev/null +++ b/admin/win/nsis_uac/UAC Readme.html @@ -0,0 +1,222 @@ + + +UAC plug-in readme + + + +

UAC plug-in

+ + +
+Interactive User (MediumIL)        Admin user(HighIL)
++++[Setup.exe]++++++++++++++       +++[Setup.exe]++++++++++++++
++                          +       +                          +
++ ***[.OnInit]************ +       + ***[.OnInit]************ +
++ * UAC::RunElevated >---+-+------>+ *                      * +
++ * NSIS.Quit()          * +       + *                      * +
++ ************************ +       + ***********||*********** +
++                          +       +            ||            +
++                          +       +            \/            +
++ ***[Sections]*********** +       + ***[Sections]*********** +
++ *                      * +    /--+-+-< UAC::Exec          * +
++ ************************ +    |  + ************************ +
++                          +    |  +                          +
++  Win32.CreateProcess() <-+----/  +                          +
++                          +       +                          +
+++++++++++++++++++++++++++++       ++++++++++++++++++++++++++++
+
+ + +

Contents

+ + + + + + + +

Plugin Functions

+Every function will try to emulate the basic NSIS instruction (of similar name) when UAC::RunElevated has not "succeeded" or running on a system that does not support elevation (Win9x/NT4)

+ + + + + +
UAC::RunElevated
Parameters:
Returns: + + + + + +
$0Win32 error code (0 on success, 1223 if user aborted elevation dialog, anything else should be treated as a fatal error)
$1If $0==0: + + + + + +
0UAC is not supported by the OS
1Started a elevated child process, the current process should act like a wrapper (Call Quit without any further processing)
2The process is already running @ HighIL (Member of admin group)
3You should call RunElevated again (This can happen if a user without admin priv. is used in the runas dialog)
+
$2If $0==0 && $1==1: ExitCode of the elevated fork process (The NSIS errlvl is also set)
$3If $0==0: 1 if the user is a member of the admin group or 0 otherwise
Description:Allows non-admin/UAC.LUA users to re-spawn the installer as another user and UAC.Admin users to elevate.
+ + + + + + +
UAC::Unload
Parameters:
Returns:
Description:Cleanup, you must call this function in .OnInstFailed, .onUserAbort and .OnInstSuccess
+ + + + + +
UAC::Exec
Parameters:<INT:ShowWindow> <STR:App> <STR:Parameters> <STR:WorkingDir>
Returns: + + +
$0Win32 error code, 0 on success (ErrorFlag is also set on error)
+ + + + +
UAC::ExecWait
Parameters:<INT:ShowWindow> <STR:App> <STR:Parameters> <STR:WorkingDir>
Returns: + + + +
$0Win32 error code, 0 on success (ErrorFlag is also set on error)
$1Exitcode of new process
+ + + + +
UAC::ShellExec
Parameters:<STR:Verb> <INT:ShowWindow> <STR:App> <STR:Parameters> <STR:WorkingDir>
Returns: + + +
$0Win32 error code, 0 on success (ErrorFlag is also set on error)
+ + + + +
UAC::ShellExecWait
Parameters:<STR:Verb> <INT:ShowWindow> <STR:App> <STR:Parameters> <STR:WorkingDir>
Returns: + + + +
$0Win32 error code, 0 on success (ErrorFlag is also set on error)
$1Exitcode of new process
+ + + + + +
UAC::IsAdmin
Parameters:
Returns:$0 (BOOL) result
Description:Check current thread/process token for a non-deny admin group SID entry
+ + + + + +
UAC::ExecCodeSegment
Parameters:<INT:NSISFunctionAddress>
Returns:[None] (ErrorFlag is set on error)
Description:Calls NSIS function in LUA/outer instance (If you use instructions that alter the UI or the stack/variables in the code segment (StrCpy,Push/Pop/Exch,DetailPrint etc.) they will affect the hidden wrapper installer and not "your" installer instance)
+ + + + + +
UAC::StackPush
Parameters:<STR:String>
Returns:[None] (ErrorFlag is set on error)
Description:Push to outer instance stack (For use with UAC::ExecCodeSegment)
+ + + + + +
UAC::GetOuterHwnd
Parameters:
Returns:$0 HWNDPARENT of outer instance
Description:For use with ${UAC.RunElevatedAndProcessMessages}
+ + + + + +
UAC::SupportsUAC
Parameters:
Returns:$0 !=0 if supported
Description:Check if the OS supports UAC (And the user has UAC turned on) This function only tests if UAC is active, will return 0 on NT5 even though runas is implemented on those platforms, will also return 0 on NT6+ if UAC is off. You should only call this function during testing, NOT to determine if you can call UAC::RunElevated
+ + + + +
UAC::GetElevationType
Parameters:
Returns: + + +
$0TOKEN_ELEVATION_TYPE: + + + + + +
0Unsupported/Failed (ErrorFlag is also set)
1TokenElevationTypeDefault: User is not using a split token (UAC disabled)
2TokenElevationTypeFull: UAC enabled, the (current) process is elevated
3TokenElevationTypeLimited: UAC enabled, the process is not elevated
+
+ +
+ + + + + +

Language support

+

If the plugin is built with FEAT_CUSTOMRUNASDLG_TRANSLATE (Enabled by default), +you can extract a file named UAC.LNG to $pluginsdir. +It is a ini file with the following sections: +

+[MyRunAsCfg]
+;Set to 1 to disable the radio button
+DisableCurrUserOpt=
+;Set to 1 to hide the radio button
+HideCurrUserOpt=
+
+[MyRunAsStrings]
+DlgTitle=Hello There!
+HelpText=Just do your thing!
+;Label for current user radio button, %s is replaced with result of GetUserNameEx(NameSamCompatible,...)
+OptCurrUser=Self service (%s)
+OptOtherUser=Run as someone:
+UserName=Who:
+Pwd=PIN:
+OK=Okey!
+Cancel=No Way
+
+ +

Known Issues

+
    +
  • UACPI.KI#1: DetailPrint in outer process is ignored +
  • UACPI.KI#2: Elevation can fail if the installer is located on a remote share that requires authentication +
+
+ + +

Glossary

+
    +
  • AAM: Admin Approval Mode +
  • IL: Integrity level (Part of the new MIC/WIC security levels added to NT6) +
  • LUA: Limited/Least-privilege User Account +
  • MIC: Mandatory Integrity Controls (Now known as WIC) +
  • UAC: User Account Control (Part of the UAP umbrella) +
  • UAP: User Account Protection +
  • WIC: Windows Integrity Controls +
  • Win32 error code: Standard windows error codes, ERROR_??? +
+
+ + diff --git a/admin/win/nsis_uac/UAC.nsh b/admin/win/nsis_uac/UAC.nsh new file mode 100755 index 000000000..b21e72ff4 --- /dev/null +++ b/admin/win/nsis_uac/UAC.nsh @@ -0,0 +1,191 @@ +/* +======================= +UAC helper include file +....................... + +Macros starting with UAC.I should only be called from the installer and vice versa for UAC.U macros. + +*/ +!ifndef UAC_HDR__INC +!define UAC_HDR__INC +!include LogicLib.nsh + +!define UAC.RunElevatedAndProcessMessages 'UAC::RunElevated ' +!define UAC.Unload 'UAC::Unload ' +!define UAC.StackPush 'UAC::StackPush ' + +/*!macro _UAC.BuildOnInitElevationFunc _funcprefix +Function ${_funcprefix}onInit +!ifmacrodef +FunctionEnd +!macroend*/ + +!macro _UAC.GenerateSimpleFunction _funcprefix _funcName _funcCode +Function ${_funcprefix}${_funcName} +${_funcCode} +#messagebox mb_ok "${_funcprefix}${_funcName}" +FunctionEnd +!macroend + +!macro _UAC.TryDef _d _v +!ifndef ${_d} +!define ${_d} "${_v}" +!endif +!macroend + +!macro _UAC.InitStrings _modeprefix +!insertmacro _UAC.TryDef UACSTR.UnDataFile "UAC.dat" +!insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvWinErr "Unable to elevate , error $0" +!ifNdef __UNINSTALL__ + !insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvAbortReqAdmin "This installer requires admin access, aborting!" + !insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvMustTryAgain "This installer requires admin access, try again" + !else + !insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvAbortReqAdmin "This uninstaller requires admin access, aborting!" + !insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvMustTryAgain "This uninstaller requires admin access, try again" + !endif +!macroend + +!ifmacroNdef _UAC.GenerateUninstallerTango +!macro _UAC.GenerateUninstallerTango UninstallerFileName +!ifdef __GLOBAL__ + !error "UAC: Needs to be called inside a function" + !endif +!ifNdef __UNINSTALL__ + !error "UAC: _UAC.GenerateUninstallerTango should only be called by uninstaller, see http://forums.winamp.com/showthread.php?threadid=280330" + !endif +!ifNdef UAC_UNINSTALLERTANGOFORALLPLATFORMS + !include WinVer.nsh + !endif +!insertmacro _UAC.InitStrings 'U.' +ReadIniStr $0 "$ExeDir\${UACSTR.UnDataFile}" UAC "Un.Ready" +${IF} $0 != 1 +!ifNdef UAC_UNINSTALLERTANGOFORALLPLATFORMS +${AndIf} ${AtLeastWinVista} +!endif + InitPluginsDir + WriteIniStr "$PluginsDir\${UACSTR.UnDataFile}" UAC "Un.Ready" 1 + CopyFiles /SILENT "$EXEPATH" "$PluginsDir\${UninstallerFileName}" + StrCpy $0 "" + ${IfThen} ${Silent} ${|} StrCpy $0 "/S " ${|} + ExecWait '"$PluginsDir\${UninstallerFileName}" $0/NCRC _?=$INSTDIR' $0 + SetErrorLevel $0 + Quit + ${EndIf} +!macroend +!endif + +!ifmacroNdef _UAC.GenerateOnInitElevationCode +!macro _UAC.GenerateOnInitElevationCode _modeprefix +!ifndef __FUNCTION__ + !error "UAC: Needs to be called inside a function" + !endif +!insertmacro _UAC.InitStrings ${_modeprefix} +!define _UAC.GOIECUniq L${__LINE__} +UAC_Elevate_${_UAC.GOIECUniq}: +UAC::RunElevated +StrCmp 1223 $0 UAC_ElevationAborted_${_UAC.GOIECUniq} ; UAC dialog aborted by user? +StrCmp 0 $0 0 UAC_Err_${_UAC.GOIECUniq} ; Error? +StrCmp 1 $1 0 UAC_Success_${_UAC.GOIECUniq} ;Are we the real deal or just the wrapper? +Quit +UAC_Err_${_UAC.GOIECUniq}: +MessageBox mb_iconstop "${UACSTR.${_modeprefix}ElvWinErr}" +Abort +UAC_ElevationAborted_${_UAC.GOIECUniq}: +MessageBox mb_iconstop "${UACSTR.${_modeprefix}ElvAbortReqAdmin}" +Abort +UAC_Success_${_UAC.GOIECUniq}: +# if $0==0 && $3==1, we are a member of the admin group (Any OS) +# if $0==0 && $1==0, UAC not supported (Probably 1:elevated instance, perform page jump +var hKey # Reg hive +var hSelModeAdminRadio +var StartMenuFolder + +!macro SetMode IsAdmin +!if "${IsAdmin}" > 0 + SetShellVarContext all + StrCpy $InstMode 1 + StrCpy $hKey HKLM + !else + SetShellVarContext current + StrCpy $InstMode 0 + StrCpy $hKey HKCU + !endif +!macroend + +Function .OnInit +!insertmacro SetMode 0 +${GetParameters} $R9 +${GetOptions} "$R9" UAC $0 ;look for special /UAC:???? parameter (sort of undocumented) +${Unless} ${Errors} + UAC::IsAdmin + ${If} $0 < 1 + SetErrorLevel 666 ;special return value for outer instance so it knows we did not have admin rights + Quit + ${EndIf} + !insertmacro SetMode 1 + StrCpy $InstMode 2 + ${EndIf} +FunctionEnd + +Function onGuiInit +${If} $InstMode >= 2 + ${UAC.GetOuterInstanceHwndParent} $0 + ${If} $0 <> 0 + System::Call /NOUNLOAD "*(i,i,i,i)i.r1" + System::Call /NOUNLOAD 'user32::GetWindowRect(i $0,i r1)i.r2' + ${If} $2 <> 0 + System::Call /NOUNLOAD "*$1(i.r2,i.r3)" + System::Call /NOUNLOAD 'user32::SetWindowPos(i $hwndParent,i0,ir2,ir3,i0,i0,i 4|1)' + ${EndIf} + ShowWindow $hwndParent ${SW_SHOW} + ShowWindow $0 ${SW_HIDE} ;hide outer instance installer window + System::Free $1 + ${EndIf} + ${EndIf} +FunctionEnd + +Function Un.OnInit +!insertmacro SetMode 0 +ReadRegDWORD $0 HKLM "${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" InstMode ;We saved the "mode" in the installer +${If} $0 U> 0 + ; If it was installed for all users, we have to be admin to uninstall it + ${UAC.U.Elevate.AdminOnly} "${UNINSTALLER_NAME}" + !insertmacro SetMode 1 + ${EndIf} +FunctionEnd + +Function onAbort +${UAC.Unload} +FunctionEnd + +${UAC.AutoCodeUnload} 1 ;Auto-generate .OnInstFailed and .OnInstSuccess functions + +!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipPageInElvModePreCB +!insertmacro MUI_PAGE_WELCOME +Page Custom ModeSelectionPageCreate ModeSelectionPageLeave +!define MUI_PAGE_CUSTOMFUNCTION_PRE CmpntsPreCB +!insertmacro MUI_PAGE_COMPONENTS +!define MUI_PAGE_CUSTOMFUNCTION_PRE DirPreCB +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_STARTMENU 1 $StartMenuFolder +!insertmacro MUI_PAGE_INSTFILES +!define MUI_FINISHPAGE_TITLE_3LINES +!define MUI_FINISHPAGE_RUN +!define MUI_FINISHPAGE_RUN_FUNCTION FinishRunCB +!insertmacro MUI_PAGE_FINISH +!define MUI_WELCOMEPAGE_TITLE_3LINES +!insertmacro MUI_UNPAGE_WELCOME +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_LANGUAGE "English" + +Function CmpntsPreCB +GetDlgItem $0 $hwndparent 3 +${IfThen} $InstMode >= 1 ${|} EnableWindow $0 0 ${|} ;prevent user from going back and selecting single user so noobs don't end up installing as the wrong user +FunctionEnd + +Function SkipPageInElvModePreCB +${IfThen} $InstMode > 1 ${|} Abort ${|} ;skip this page so we get to the mode selection page +FunctionEnd + +Function ModeSelectionPageCreate +${If} $InstMode > 1 + StrCpy $InstMode 1 + Abort ;skip this page and contine where the "parent" would have gone + ${EndIf} +!insertmacro MUI_HEADER_TEXT_PAGE "Select install type" "Blah blah blah blah" +nsDialogs::Create /NOUNLOAD 1018 +Pop $0 +${NSD_CreateLabel} 0 20u 75% 20u "Blah blah blah blah select install type..." +Pop $0 +System::Call "advapi32::GetUserName(t.r0, *i ${NSIS_MAX_STRLEN}r1) i.r2" +${NSD_CreateRadioButton} 0 40u 75% 15u "Single User ($0)" +Pop $0 +${IfThen} $InstMode U< 1 ${|} SendMessage $0 ${BM_SETCHECK} 1 0 ${|} +${NSD_CreateRadioButton} 0 60u 75% 15u "All users" +Pop $hSelModeAdminRadio +${IfThen} $InstMode U> 0 ${|} SendMessage $hSelModeAdminRadio ${BM_SETCHECK} 1 0 ${|} +nsDialogs::Show +FunctionEnd + +!macro EnableCtrl dlg id state +push $language +GetDlgItem $language ${dlg} ${id} +EnableWindow $language ${state} +pop $language +!macroend + +Function ModeSelectionPageLeave +SendMessage $hSelModeAdminRadio ${BM_GETCHECK} 0 0 $9 +UAC::IsAdmin +${If} $9 U> 0 + ${If} $0 <> 0 + !insertmacro SetMode 1 + ${Else} + System::Call /NoUnload 'user32::GetWindowText(i $HwndParent,t.R1,i ${NSIS_MAX_STRLEN})' ;get original window title + System::Call /NoUnload 'user32::SetWindowText(i $HwndParent,t "${ELEVATIONTITLE}")' ;set out special title + StrCpy $2 "" ;reset special return, only gets set when sub process is executed, not when user cancels + !insertmacro EnableCtrl $HWNDParent 1 0 ;Disable next button, just because it looks good ;) + ${UAC.RunElevatedAndProcessMessages} + !insertmacro EnableCtrl $HWNDParent 1 1 + System::Call 'user32::SetWindowText(i $HwndParent,t "$R1")' ;restore title + ${If} $2 = 666 ;our special return, the new process was not admin after all + MessageBox mb_iconExclamation "You need to login with an account that is a member of the admin group to continue..." + Abort + ${ElseIf} $0 = 1223 ;cancel + Abort + ${Else} + ${If} $0 <> 0 + ${If} $0 = 1062 + MessageBox mb_iconstop "Unable to elevate, Secondary Logon service not running!" + ${Else} + MessageBox mb_iconstop "Unable to elevate, error $0 ($1,$2,$3)" + ${EndIf} + Abort + ${EndIf} + ${EndIf} + Quit ;We now have a new process, the install will continue there, we have nothing left to do here + ${EndIf} +${EndIf} +FunctionEnd + +Function DirPreCB +${If} $InstDir == "" + ${If} $InstMode U> 0 + StrCpy $InstDir "$ProgramFiles\${APPNAME}" + ${Else} + StrCpy $InstDir "$APPDATA\${APPNAME}" + ${EndIf} + ${EndIf} +FunctionEnd + +Function FinishRunCB +UAC::Exec "" "Notepad.exe" "$Windir\Win.INI" "$InstDir" +FunctionEnd + +Function CreateSMShortcuts +StrCpy ${SMSUBDIR} $9 ;stupid sync +CreateDirectory "$SMPrograms\${SMSUBDIR}" +CreateShortcut "$SMPrograms\${SMSUBDIR}\${APPNAME}.lnk" "$Windir\Notepad.exe" +CreateShortcut "$SMPrograms\${SMSUBDIR}\Uninstall ${APPNAME}.lnk" "$InstDir\${UNINSTALLER_NAME}" +FunctionEnd +Function CreateDeskShortcuts +CreateShortcut "$Desktop\${APPNAME}.lnk" "$Windir\Notepad.exe" +FunctionEnd + +Section "!Required files" +SectionIn RO +SetOutPath - +!insertmacro _UAC.DbgDetailPrint ;some debug info, useful during testing +;Install files here... +WriteUninstaller "$InstDir\${UNINSTALLER_NAME}" +${registry::Write} "$hKey\${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" DisplayName "${APPNAME}" REG_SZ $0 +${registry::Write} "$hKey\${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" UninstallString "$InstDir\${UNINSTALLER_NAME}" REG_SZ $0 +${registry::Write} "$hKey\${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" InstMode $InstMode REG_DWORD $0 +${registry::Unload} +SectionEnd + +Section "Startmenu Shortcuts" +StrCpy $9 ${SMSUBDIR} ;this is stupid as hell, we need correct ${SMSUBDIR} in the outer process, this is the only way (plugins cannot enum "custom" var's AFAIK) +${UAC.CallFunctionAsUser} CreateSMShortcuts +SectionEnd +Section "Desktop Shortcut" +${UAC.CallFunctionAsUser} CreateDeskShortcuts +SectionEnd + +Section Uninstall +Delete "$InstDir\${UNINSTALLER_NAME}" +Delete "$SMPrograms\${SMSUBDIR}\${APPNAME}.lnk" +Delete "$SMPrograms\${SMSUBDIR}\Uninstall ${APPNAME}.lnk" +RMDir "$SMPrograms\${SMSUBDIR}" +Delete "$Desktop\${APPNAME}.lnk" + +RMDir "$InstDir" +${registry::DeleteKey} "$hKey\${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" $0 +${registry::Unload} +SectionEnd \ No newline at end of file diff --git a/admin/win/nsis_uac/UAC_Uninstaller.nsi b/admin/win/nsis_uac/UAC_Uninstaller.nsi new file mode 100755 index 000000000..3cef1814c --- /dev/null +++ b/admin/win/nsis_uac/UAC_Uninstaller.nsi @@ -0,0 +1,49 @@ +/* +This script was made in response to http://forums.winamp.com/showthread.php?threadid=280330 +It is a ugly hack and is mostly here just to have a solution right now. +Hopefully, NSIS will add support for changing the RequestExecutionLevel of the uninstaller +This code inspired the _UAC.GenerateUninstallerTango macro (called by ${UAC.U.Elevate.AdminOnly} unless you define UAC_DISABLEUNINSTALLERTANGO) +*/ + +RequestExecutionLevel user /* RequestExecutionLevel REQUIRED! */ +!define APPNAME "UAC_Uninstaller" +Name "${APPNAME}" +OutFile "${APPNAME}.exe" +ShowInstDetails show +!include LogicLib.nsh + +!define UNINSTALLER_UACDATA "uac.ini" +!define UNINSTALLER_NAME "Uninstall FooBarBaz" + +Function un.onInit +ReadIniStr $0 "$ExeDir\${UNINSTALLER_UACDATA}" UAC "Un.First" +${IF} $0 != 1 + ;SetSilent silent + InitPluginsDir + WriteIniStr "$PluginsDir\${UNINSTALLER_UACDATA}" UAC "Un.First" 1 + CopyFiles /SILENT "$EXEPATH" "$PluginsDir\${UNINSTALLER_NAME}.exe" + StrCpy $0 "" + ${IfThen} ${Silent} ${|} StrCpy $0 "/S " ${|} + ExecWait '"$PluginsDir\${UNINSTALLER_NAME}.exe" $0/NCRC _?=$INSTDIR' $0 + SetErrorLevel $0 + Quit + ${EndIf} + +# UAC code goes here ... +FunctionEnd + +Section +WriteUninstaller "$exedir\${UNINSTALLER_NAME}.exe" +SetAutoClose true +DetailPrint "Uninstalling..." +Sleep 1111 +Exec '"$exedir\${UNINSTALLER_NAME}.exe"' +SectionEnd + +Section uninstall +MessageBox mb_ok "My filename is: $EXEFILE" +Delete "$instdir\${UNINSTALLER_NAME}.exe" +Delete "$instdir\${APPNAME}.exe" ;delete generated installer aswell, this is just a sample script +SectionEnd + +page InstFiles \ No newline at end of file diff --git a/admin/win/nsis_uac/resource.h b/admin/win/nsis_uac/resource.h new file mode 100755 index 000000000..933adac5b --- /dev/null +++ b/admin/win/nsis_uac/resource.h @@ -0,0 +1,24 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by resource.rc +// +#define IDD_MYRUNAS 101 +#define IDC_RUNASCURR 1000 +#define IDC_RUNASSPEC 1001 +#define IDC_SHICON 1002 +#define IDC_HELPTEXT 1003 +#define IDC_USERNAME 1004 +#define IDC_PASSWORD 1005 +#define IDC_LBLUSER 1007 +#define IDC_LBLPWD 1008 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1009 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/admin/win/nsis_uac/resource.rc b/admin/win/nsis_uac/resource.rc new file mode 100755 index 000000000..3c90e6bea --- /dev/null +++ b/admin/win/nsis_uac/resource.rc @@ -0,0 +1,109 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" +#include "uac.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MYRUNAS DIALOG DISCARDABLE 0, 0, 250, 145 +STYLE DS_MODALFRAME | DS_NOIDLEMSG | DS_SETFOREGROUND | DS_FIXEDSYS | + DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "&OK",IDOK,132,122,50,14 + PUSHBUTTON "Ca&ncel",IDCANCEL,188,122,50,14 + ICON "",IDC_SHICON,7,7,20,20 + LTEXT "",IDC_HELPTEXT,34,7,204,35 + CONTROL "",IDC_RUNASCURR,"Button",BS_AUTORADIOBUTTON,20,49,218, + 10 + CONTROL "",IDC_RUNASSPEC,"Button",BS_AUTORADIOBUTTON,20,65,218, + 10 + LTEXT "&User name:",IDC_LBLUSER,20,84,42,16 + EDITTEXT IDC_USERNAME,63,83,175,14,ES_AUTOHSCROLL + LTEXT "&Password:",IDC_LBLPWD,20,102,42,20 + EDITTEXT IDC_PASSWORD,63,100,175,14,ES_PASSWORD | ES_AUTOHSCROLL +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_MYRUNAS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 238 + TOPMARGIN, 7 + BOTTOMMARGIN, 136 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "#include ""uac.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/admin/win/nsis_uac/uac.cpp b/admin/win/nsis_uac/uac.cpp new file mode 100755 index 000000000..6ccbc0424 --- /dev/null +++ b/admin/win/nsis_uac/uac.cpp @@ -0,0 +1,1518 @@ +//Copyright (C) 2007 Anders Kjersem. Licensed under the zlib/libpng license, see License.txt for details. +/* +UAC plugin for NSIS +=================== +Compiled with VC6+PlatformSDK (StdCall & MinimizeSize) + + +Todo: +----- +¤GetCurrentDir in elevated parent and pass along to outer process for Exec* (or somekind of ipc to request it if workingdir param is empty) +X¤Check if secondary logon service is running in SysElevationPresent() on NT5 +¤Use IsUserAnAdmin? MAKEINTRESOURCE(680) export on 2k (it even exists on NT4?) //http://forums.winamp.com/showthread.php?s=&threadid=195020 +¤AllowSetForegroundWindow +¤Use RPC instead of WM_COPYDATA for IPC +¤Autodetect "best" default admin user in MyRunAs +¤Use ChangeWindowMessageFilter so we can get >WM_USER msg success feedback and possibly fill the log with detailprints +¤Hide IPC window inside inner instance window? (Could this add unload problems?) +¤CREATE_PRESERVE_CODE_AUTHZ_LEVEL? http://msdn2.microsoft.com/en-us/library/ms684863.aspx +¤UpdateProcThreadAttribute? +¤Consent UI on XP ? +¤All langs in single file; [MyRunAsStrings]>LangSections != 0 then load strings from [langid] sections +¤BroadcastSystemMessage to help with SetForeground +¤UAC::StackPop + + +Notes: +------ +Primary integrity levels: +Name SID RID +Low Mandatory Level S-1-16-4096 0x1000 +Medium Mandatory Level S-1-16-8192 0x2000 +High Mandatory Level S-1-16-12288 0x3000 +System Mandatory Level S-1-16-16384 0x4000 + +*/ + +#define UAC_HACK_Clammerz //ugly messagebox focus hack for .onInit +#define UAC_HACK_FGWND1 //super ugly fullscreen invisible window for focus tricks + +#define UAC_INITIMPORTS +#include "UAC.h" +#include //CoInitialize +#include "NSISUtil.h" +using namespace NSIS; +NSISUTIL_INIT(); + + +#define ERRAPP_BADIPCSRV (0x20000000|1) +#define SW_INVALID ((WORD)-1) +#define IPCTOUT_DEF (1000*3) //default timeout for IPC messages +#define IPCTOUT_SHORT 1500 +#define IPCTOUT_LONG (IPCTOUT_DEF*2) + +enum _IPCSRVWNDMSG +{ + IPC_GETEXITCODE=WM_USER, //Get exit-code of the process spawned by the last call to ExecWait/ShellExecWait + IPC_ELEVATEAGAIN, + IPC_GETSRVPID, //Get PID of outer process + IPC_GETSRVHWND, //Get $HWNDParent of outer process + IPC_EXECCODESEGMENT, //wp:pos | lp:hwnd | returns ErrorCode+1 + IPC_GETOUTERPROCESSTOKEN, +#ifdef UAC_HACK_FGWND1 + IPC_HACKFINDRUNAS, +#endif +}; + +enum _COPYDATAID +{ + CDI_SHEXEC=666, //returns WindowsErrorCode+1 + CDI_SYNCVAR, + CDI_STACKPUSH, +}; + +typedef struct +{ + UINT VarId; + NSISCH buf[ANYSIZE_ARRAY]; +} IPC_SYNCVAR; + +typedef struct +{ + HWND hwnd; + bool Wait; + bool UseCreateProcess; + WORD ShowMode; + NSISCH*strExec; + NSISCH*strParams; + NSISCH*strWorkDir; + NSISCH*strVerb; + NSISCH buf[ANYSIZE_ARRAY]; +} IPC_SHEXEC; + + +typedef struct +{ + HINSTANCE hInstance; + HWND hSrvIPC; + BYTE DllRef; + bool UseIPC; + bool CheckedIPCParam; + UINT NSISStrLen; + //IPC Server stuff: + HANDLE hElevatedProcess; + HANDLE threadIPC; + DWORD LastWaitExitCode;//Exit code of process started from last call to ExecWait/ShellExecWait + NSIS::extra_parameters*pXParams; + bool ElevateAgain; + //DelayLoadedModules: + HMODULE hModAdvAPI; +} GLOBALS; + + +GLOBALS g = {0}; + + +void StopIPCSrv(); +DWORD _GetElevationType(TOKEN_ELEVATION_TYPE* pTokenElevType); +bool GetIPCSrvWndFromParams(HWND&hwndOut); + + + +#if _MSC_VER >= 1400 //MSVC 2005 wants to pull in the CRT, let's try to help it out +void* __cdecl memset(void*mem,int c,size_t len) +{ + char *p=(char*)mem; + while (len-- > 0){*p++=c;} + return mem; +} +#endif + + + +FORCEINLINE NSISCH* GetIPCWndClass() { return _T("NSISUACIPC"); } +FORCEINLINE bool StrCmpI(LPCTSTR s1,LPCTSTR s2) {return 0==lstrcmpi(s1,s2);} +LPTSTR StrNextChar(LPCTSTR Str) { return CharNext(Str); } +bool StrContainsWhiteSpace(LPCTSTR s) { if (s) {while(*s && *s>_T(' '))s=StrNextChar(s);if (*s)return true;}return false; } + +DWORD GetSysVer(bool Major=true) +{ + OSVERSIONINFO ovi = { sizeof(ovi) }; + if ( !GetVersionEx(&ovi) ) return 0; + return Major ? ovi.dwMajorVersion : ovi.dwMinorVersion; +} +#define GetOSVerMaj() (GetSysVer(true)) +#define GetOSVerMin() (GetSysVer(false)) + +UINT_PTR StrToUInt(LPTSTR s,bool ForceHEX=false,BOOL*pFoundBadChar=0) +{ + UINT_PTR v=0; + BYTE base=ForceHEX?16:10; + if (pFoundBadChar)*pFoundBadChar=false; + if ( !ForceHEX && *s=='0' && ((*(s=StrNextChar(s)))&~0x20)=='X' && (s=StrNextChar(s)) )base=16; + for (TCHAR c=*s; c; c=*(s=StrNextChar(s)) ) + { + if (c >= _T('0') && c <= _T('9')) c-='0'; + else if (base==16 && (c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') c=(c & 7) +9; + else + { + if (pFoundBadChar /*&& c!=' '*/)*pFoundBadChar=true; + break; + } + v*=base;v+=c; + } + return v; +} + +LPTSTR FindExePathEnd(LPTSTR p) +{ + if ( *p=='"' && *(++p) ) + { + while( *p && *p!='"' )p=StrNextChar(p); + if (*p) + p=StrNextChar(p); + else + return 0; + } + else + if ( *p!='/' )while( *p && *p!=' ' )p=StrNextChar(p); + return p; +} + + +#ifdef FEAT_MSRUNASDLGMODHACK +HHOOK g_MSRunAsHook; +void MSRunAsDlgMod_Unload(void*hook) +{ + if (hook) + { + //ASSERT(g_MSRunAsHook==hook); + UnhookWindowsHookEx((HHOOK)hook); + //g_MSRunAsHook=0; + } +} +LRESULT CALLBACK MSRunAsDlgMod_ShellProc(int nCode,WPARAM wp,LPARAM lp) +{ + CWPRETSTRUCT*pCWPS; + if (nCode >= 0 && (pCWPS=(CWPRETSTRUCT*)lp) && WM_INITDIALOG==pCWPS->message) + { + TCHAR buf[30]; + GetClassName(pCWPS->hwnd,buf,COUNTOF(buf)); + if (!lstrcmpi(buf,_T("#32770"))) + { + const UINT IDC_USRSAFER=0x106,IDC_OTHERUSER=0x104,IDC_SYSCRED=0x105; + GetClassName(GetDlgItem(pCWPS->hwnd,IDC_SYSCRED),buf,COUNTOF(buf)); + if (!lstrcmpi(buf,_T("SysCredential"))) //make sure this is the run as dialog + { + MySndDlgItemMsg(pCWPS->hwnd,IDC_USRSAFER,BM_SETCHECK,BST_UNCHECKED); + MySndDlgItemMsg(pCWPS->hwnd,IDC_OTHERUSER,BM_CLICK); + } + } + } + return CallNextHookEx(g_MSRunAsHook,nCode,wp,lp); +} +void* MSRunAsDlgMod_Init() +{ + if(GetOSVerMaj()!=5 || GetOSVerMin()<1)return NULL;//only XP/2003 + return g_MSRunAsHook=SetWindowsHookEx(WH_CALLWNDPROCRET,MSRunAsDlgMod_ShellProc,0,GetCurrentThreadId()); +} +#endif + +DWORD DllSelfAddRef() +{ + NSISCH buf[MAX_PATH*5];//Lets hope $pluginsdir is shorter than this, only special builds could break this + DWORD len=GetModuleFileName(g.hInstance,buf,MAX_PATH*5); + if ( len && len FreeLibrary(g.hModAdvAPI); + } +} + +DWORD DelayLoadGetProcAddr(void**ppProc,HMODULE hLib,LPCSTR Export) +{ + ASSERT(ppProc && hLib && Export); + if (!*ppProc) + { + *ppProc=GetProcAddress(hLib,Export); + if (!*ppProc)return GetLastError(); + } + return NO_ERROR; +} + +DWORD DelayLoadDlls() +{ + +#ifdef UNICODE +# define __DLD_FUNCSUFFIX "W" +# else +# define __DLD_FUNCSUFFIX "A" +# endif + + if (!g.hModAdvAPI) //using g.hModAdvAPI to test if this is the first time we have been called + { + struct + { + HMODULE*pMod; + LPCSTR DllName;//NOTE: Always using ANSI strings to save a couple of bytes + } + dld[]= + { + {&g.hModAdvAPI,"AdvAPI32"}, + {0} + }; + DWORD ec; + UINT o; + + for (o=0; dld[o].pMod; ++o) + if ( !(*dld[o].pMod=LoadLibraryA(dld[o].DllName)) ) + return GetLastError(); + + struct + { + HMODULE hMod; + void**ppProc; + LPCSTR Export; + bool Optional; + } + dldprocs[]= + { + {GetModuleHandle(_T("USER32")),(void**)&_AllowSetForegroundWindow,"AllowSetForegroundWindow",true}, + {g.hModAdvAPI,(void**)&_OpenProcessToken, "OpenProcessToken"}, + {g.hModAdvAPI,(void**)&_OpenThreadToken, "OpenThreadToken"}, + {g.hModAdvAPI,(void**)&_GetTokenInformation, "GetTokenInformation"}, + {g.hModAdvAPI,(void**)&_AllocateAndInitializeSid, "AllocateAndInitializeSid"}, + {g.hModAdvAPI,(void**)&_FreeSid, "FreeSid"}, + {g.hModAdvAPI,(void**)&_EqualSid, "EqualSid"}, + {g.hModAdvAPI,(void**)&_CheckTokenMembership, "CheckTokenMembership",true}, + #ifdef FEAT_CUSTOMRUNASDLG + {g.hModAdvAPI,(void**)&_GetUserName, "GetUserName" __DLD_FUNCSUFFIX}, + {g.hModAdvAPI,(void**)&_CreateProcessWithLogonW,"CreateProcessWithLogonW",true}, + {LoadLibraryA("SECUR32"),(void**)&_GetUserNameEx,"GetUserNameEx" __DLD_FUNCSUFFIX,true},//We never free this library + #endif + {0} + }; +//#undef __DLD_FUNCSUFFIX + for (o=0; dldprocs[o].hMod; ++o) + if (ec=DelayLoadGetProcAddr(dldprocs[o].ppProc,dldprocs[o].hMod,dldprocs[o].Export) && !dldprocs[o].Optional) + { + TRACEF("DelayLoadDlls failed to find %s in %X\n",dldprocs[o].Export,dldprocs[o].hMod); + return ec; + } + } + return NO_ERROR; +} + +void AllowOuterInstanceWindowFocus() +{ + if (g.UseIPC) + { + DWORD_PTR MsgRet; + if (!SendIPCMsg(IPC_GETSRVPID,0,0,MsgRet,IPCTOUT_SHORT) && MsgRet && _AllowSetForegroundWindow)_AllowSetForegroundWindow(MsgRet); + } +} + +DWORD SyncVars(HWND hwndNSIS) +{ + DWORD i,ec=NO_ERROR; + IPC_SYNCVAR*pSV=0; + if (!g.UseIPC)return NO_ERROR; + g.NSISStrLen=NSIS::StrSize; + TRACEF("SyncVars: g.NSISStrLen=%d\n",g.NSISStrLen);ASSERT(g.NSISStrLen>10); + DWORD cbStruct=FIELD_OFFSET(IPC_SYNCVAR,buf[g.NSISStrLen+1]); + pSV=(IPC_SYNCVAR*)MemAlloc(cbStruct); + if (!pSV) + goto die_GLE; + else + { + COPYDATASTRUCT cds={CDI_SYNCVAR,cbStruct,pSV}; + for (i=0;i<__INST_LAST && !ec;++i) + { + pSV->VarId=i; + lstrcpyn(pSV->buf,GetVar(i),g.NSISStrLen); + DWORD MsgRet;//TRACEF("SyncVars: (%d)%s|\n",i,pSV->buf); + if (!(ec=SendIPCMsg(WM_COPYDATA,(WPARAM)hwndNSIS,(LPARAM)&cds,MsgRet,3000 )))ec=MsgRet-1; + } + } + return ec; +die_GLE: + return GetLastError(); +} + +DWORD _Exec(HWND hwnd,NSISCH*Verb,NSISCH*Exec,NSISCH*Params,NSISCH*WorkDir,WORD ShowWnd,bool Wait,bool UseCreateProcess) +{ + DWORD ec; + NSISCH*buf=0; + SHELLEXECUTEINFO sei={sizeof(SHELLEXECUTEINFO)}; + sei.hwnd =hwnd; + sei.nShow =(ShowWnd!=SW_INVALID)?ShowWnd:SW_NORMAL; + sei.fMask =SEE_MASK_FLAG_DDEWAIT; + sei.lpFile =(Exec&&*Exec) ?Exec:0; + sei.lpParameters=(Params&&*Params) ?Params:0; + sei.lpDirectory =(WorkDir&&*WorkDir) ?WorkDir:0; + sei.lpVerb =(Verb&&*Verb) ?Verb:0; + TRACEF("_Exec:%X|%s|%s|%s|wait=%d useCreateProc=%d ShowWnd=%d useShowWnd=%d\n",hwnd,Exec,Params,WorkDir,Wait,UseCreateProcess,ShowWnd,ShowWnd!=SW_INVALID); + if (UseCreateProcess) + { + STARTUPINFO si={sizeof(STARTUPINFO)}; + if (ShowWnd != SW_INVALID) + { + si.dwFlags|=STARTF_USESHOWWINDOW; + si.wShowWindow=sei.nShow; + } + PROCESS_INFORMATION pi; + const NSISCH*Q=( (*Exec!='"') && (*Params) && StrContainsWhiteSpace(Exec)) ? _T("\"") : _T("");//Add extra quotes to program part of command-line? + const DWORD len= ((*Q)?2:0) + lstrlen(Exec) + 1 + lstrlen(Params) + 1; + buf=(NSISCH*)NSIS::MemAlloc(len*sizeof(NSISCH)); + if (!buf)return ERROR_OUTOFMEMORY; + //Build string for CreateProcess, "[Q][Q][Space]" + wsprintf(buf,_T("%s%s%s%s%s"),Q,Exec,Q,((*Params)?_T(" "):_T("")),Params); + TRACEF("_Exec: calling CreateProcess>%s< in >%s< addedQ=%d show=%u\n",buf,sei.lpDirectory,*Q,sei.nShow); + if ( !CreateProcess(0,buf,0,0,false,0,0,sei.lpDirectory,&si,&pi) ) goto die_GLE; + CloseHandle(pi.hThread); + sei.hProcess=pi.hProcess; + } + else + { + sei.fMask|=SEE_MASK_NOCLOSEPROCESS; + TRACEF("_Exec: calling ShellExecuteEx...\n"); + if ( !ShellExecuteEx(&sei) )goto die_GLE; + } + if (Wait) + { + WaitForSingleObject(sei.hProcess,INFINITE); + GetExitCodeProcess(sei.hProcess,&g.LastWaitExitCode); + } + else WaitForInputIdle(sei.hProcess,1500);//wait a little bit so the finish page window does not go away too fast and cause focus problems + + CloseHandle(sei.hProcess); + ec=NO_ERROR; +ret: + if (buf)NSIS::MemFree(buf); + return ec; +die_GLE: + ec=GetLastError(); + TRACEF("_Exec>%s failed with error %u (%s)\n",UseCreateProcess?"CreateProcess":"ShExec",ec,buf); + goto ret; +} + +WORD GetShowWndCmdFromStr(NSISCH*s) +{ + //NOTE: Little used modes are still supported, just not with strings, you must use the actual number or ${SW_xx} defines from WinMessages.h + struct {NSISCH*id;WORD cmd;} swcm[] = { + {_T("SW_HIDE"), SW_HIDE}, + {_T("SW_SHOW"), SW_SHOW}, + {_T("SW_RESTORE"), SW_RESTORE}, + {_T("SW_MAXIMIZE"), SW_MAXIMIZE}, + {_T("SW_MINIMIZE"), SW_MINIMIZE}, + // {_T("SW_MAX"), SW_MAXIMIZE}, + // {_T("SW_MIN"), SW_MINIMIZE}, + {_T("SW_SHOWNORMAL"), SW_SHOWNORMAL}, + //{_T("SW_NORMAL"), SW_NORMAL}, + //{_T("SW_SHOWMINIMIZED"), SW_SHOWMINIMIZED}, + //{_T("SW_SHOWMAXIMIZED"), SW_SHOWMAXIMIZED}, + //{_T("SW_SHOWNOACTIVATE"), SW_SHOWNOACTIVATE}, + //{_T("SW_SHOWNA"), SW_SHOWNA}, + //{_T("SW_SHOWMINNOACTIVE"), SW_SHOWMINNOACTIVE}, + //{_T("SW_SHOWDEFAULT"), SW_SHOWDEFAULT}, + //{_T("SW_FORCEMINIMIZE"), SW_FORCEMINIMIZE}, + {0} + }; + for (int i=0; swcm[i].id; ++i) if (StrCmpI(s,swcm[i].id)) return swcm[i].cmd; + return SW_INVALID; +} + +#define HasIPCServer() (g.UseIPC!=NULL) + +void HandleExecExport(bool CreateProc,bool Wait,HWND&hwndNSIS,int&StrSize,NSISCH*&Vars,stack_t**&StackTop,NSIS::extra_parameters*pXParams) +{ + DWORD ec=NO_ERROR,ForkExitCode=ERROR_INVALID_FUNCTION; + UINT cch=0,cbStruct; + WORD ShowWnd; + IPC_SHEXEC*pISE=0; + stack_t* const pSIVerb=CreateProc?0:StackPop();//Only ShellExec supports verb's + stack_t* const pSIShowWnd =StackPop(); + stack_t* const pSIExec =StackPop(); + stack_t* const pSIParams =StackPop(); + stack_t* const pSIWorkDir =StackPop(); + + if (ec=MaintainDllSelfRef())goto ret; + if (!pSIExec || !pSIParams || !pSIWorkDir || !pSIShowWnd || (!pSIVerb && !CreateProc)) + { + TRACE("If you see this you probably forgot that all parameters are required!\n"); + ec=ERROR_INVALID_PARAMETER; + goto ret; + } + ShowWnd=GetShowWndCmdFromStr(pSIShowWnd->text); + if (ShowWnd==SW_INVALID && *pSIShowWnd->text) + { + BOOL BadCh; + ShowWnd=StrToUInt(pSIShowWnd->text,false,&BadCh); + if (BadCh)ShowWnd=SW_INVALID; + } + TRACEF("HandleExecExport: ipc=%X (%X)\n",g.UseIPC,g.hSrvIPC); + SyncVars(hwndNSIS); + if (!g.UseIPC) //No IPC Server, we are not elevated with UAC + { + ec=_Exec(hwndNSIS,pSIVerb?pSIVerb->text:0,pSIExec->text,pSIParams->text,pSIWorkDir->text,ShowWnd,Wait,CreateProc); + if (Wait)ForkExitCode=g.LastWaitExitCode; + goto ret; + } + cch+=lstrlen(pSIExec->text)+1; + cch+=lstrlen(pSIParams->text)+1; + cch+=lstrlen(pSIWorkDir->text)+1; + if (pSIVerb)cch+=lstrlen(pSIVerb->text)+1; + cbStruct=FIELD_OFFSET( IPC_SHEXEC, buf[cch*sizeof(TCHAR)] ); + pISE=(IPC_SHEXEC*)NSIS::MemAlloc(cbStruct); + if (!pISE)ec=GetLastError(); + if (!ec) + { + DWORD_PTR MsgRet; + pISE->hwnd =hwndNSIS; + pISE->Wait =Wait; + pISE->ShowMode =ShowWnd; + pISE->UseCreateProcess=CreateProc; + //Just offsets at this point + pISE->strExec =(NSISCH*)0; + pISE->strParams =(NSISCH*)(lstrlen(pSIExec->text) +pISE->strExec+1); + pISE->strWorkDir=(NSISCH*)(lstrlen(pSIParams->text) +pISE->strParams+1); + pISE->strVerb= (NSISCH*)(lstrlen(pSIWorkDir->text)+pISE->strWorkDir+1); + lstrcpy(pISE->buf,pSIExec->text); + lstrcpy(&pISE->buf[(DWORD_PTR)pISE->strParams], pSIParams->text); + lstrcpy(&pISE->buf[(DWORD_PTR)pISE->strWorkDir],pSIWorkDir->text); + if (pSIVerb)lstrcpy(&pISE->buf[(DWORD_PTR)pISE->strVerb], pSIVerb->text); + COPYDATASTRUCT cds; + cds.dwData=CDI_SHEXEC; + cds.cbData=cbStruct; + cds.lpData=pISE; + AllowOuterInstanceWindowFocus(); + if (!(ec=SendIPCMsg(WM_COPYDATA,(WPARAM)hwndNSIS,(LPARAM)&cds,MsgRet,Wait?(INFINITE):(IPCTOUT_LONG) )))ec=MsgRet-1; + TRACEF("HandleExecExport: IPC returned %X, ec=%d\n",MsgRet,ec); + if (Wait && NO_ERROR==ec) + { + ec=SendIPCMsg(IPC_GETEXITCODE,0,0,ForkExitCode); + TRACEF("HandleExecExport(Wait): Spawned process exit code=%d",ForkExitCode); + } + } +ret: + NSIS::MemFree(pISE); + StackFreeItem(pSIShowWnd); + StackFreeItem(pSIExec); + StackFreeItem(pSIParams); + StackFreeItem(pSIWorkDir); + StackFreeItem(pSIVerb); + SetVarUINT(INST_0,ec); + if (ec)SetErrorFlag(pXParams); + if (Wait)SetVarUINT(INST_1,ForkExitCode); +} + + +bool _SupportsUAC(bool VersionTestOnly=false) +{ + TOKEN_ELEVATION_TYPE tet; + OSVERSIONINFO ovi={sizeof(ovi)}; + if (!GetVersionEx(&ovi)) + { + ASSERT(!"_SupportsUAC>GetVersionEx"); + return false; + } + if (VersionTestOnly)return ovi.dwMajorVersion>=6; + if (ovi.dwMajorVersion>=6 && _GetElevationType(&tet)==NO_ERROR) + { + const bool ret=tet!=TokenElevationTypeDefault && tet!=NULL; + TRACEF("_SupportsUAC tet=%d, returning %d\n",tet,ret); + return ret; + } + DBGONLY(TRACEF("_SupportsUAC returning false! ver=%d _GetElevationType.ret=%u\n",ovi.dwMajorVersion,_GetElevationType(&tet))); + return false; +} + +DWORD _GetElevationType(TOKEN_ELEVATION_TYPE*pTokenElevType) +{ + DWORD ec=ERROR_ACCESS_DENIED; + HANDLE hToken=0; + DWORD RetLen; + if (!pTokenElevType)return ERROR_INVALID_PARAMETER; + if (ec=DelayLoadDlls())return ec; + *pTokenElevType=(TOKEN_ELEVATION_TYPE)NULL; + if (!_SupportsUAC(true))return NO_ERROR; + if (!_OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken))goto dieLastErr; + if (!_GetTokenInformation(hToken,(_TOKEN_INFORMATION_CLASS)TokenElevationType,pTokenElevType,sizeof(TOKEN_ELEVATION_TYPE),&RetLen))goto dieLastErr; + SetLastError(NO_ERROR); +dieLastErr: + ec=GetLastError(); + CloseHandle(hToken); + TRACEF("_GetElevationType ec=%u type=%d\n",ec,*pTokenElevType); + return ec; +} + + +bool _IsUACEnabled() +{ + HKEY hKey; + bool ret=false; + if (GetSysVer()>=6 && NO_ERROR==RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),0,KEY_READ,&hKey)) + { + //Check must be !=0, see http://codereview.chromium.org/3110 & http://src.chromium.org/viewvc/chrome?view=rev&revision=2330 + //Apparently, Vista treats !=0 as UAC on, and some machines have EnableLUA=2 !! + DWORD val,type,size=sizeof(DWORD); + if (NO_ERROR==RegQueryValueEx(hKey,_T("EnableLUA"),0,&type,(LPBYTE)&val,&size) && type==REG_DWORD && val!=0) ret=true; + RegCloseKey(hKey); + } + return ret; +} + +bool SysQuery_IsServiceRunning(LPCTSTR servicename) +{ + bool retval=false; + SC_HANDLE scdbh=NULL,hsvc; + scdbh=OpenSCManager(NULL,NULL,GENERIC_READ); + if (scdbh) + { + if (hsvc=OpenService(scdbh,servicename,SERVICE_QUERY_STATUS)) + { + SERVICE_STATUS ss; + if (QueryServiceStatus(hsvc,&ss))retval=(ss.dwCurrentState==SERVICE_RUNNING); + CloseServiceHandle(hsvc); + } + } + CloseServiceHandle(scdbh); + return retval; +} + +inline bool SysNT5IsSecondaryLogonSvcRunning() +{ + return SysQuery_IsServiceRunning(_T("seclogon")); +} + +bool SysElevationPresent() //Will return false on Vista if UAC is off +{ + const DWORD vmaj=GetSysVer(); + ASSERT(vmaj<=6 && vmaj>=4); + if (vmaj==5) return true; //TODO:Check if secondary logon service is running? + if (vmaj>=6) return _IsUACEnabled(); + return false; +} + +FORCEINLINE bool SysSupportsRunAs() +{ + return GetSysVer()>=5; +} + + + + + +bool _IsAdmin() +{ + +#ifdef BUILD_XPTEST + static int _dbgOld=-1; + unsigned _dbg=(unsigned)FindExePathEnd(GetCommandLine()); + if (_dbgOld==-1){_dbg=(_dbg && *((TCHAR*)_dbg))?MessageBoxA(0,"Debug: Pretend to be admin?",GetCommandLine(),MB_YESNOCANCEL):IDCANCEL;} else _dbg=_dbgOld;_dbgOld=_dbg;TRACEF("_IsAdmin=%d|%d\n",_dbg,_dbg==IDYES); + if (_dbg!=IDCANCEL){SetLastError(0);return _dbg==IDYES;} +#endif + + BOOL isAdmin=false; + DWORD ec; + OSVERSIONINFO ovi={sizeof(ovi)}; + if (!GetVersionEx(&ovi))return false; + if (VER_PLATFORM_WIN32_NT != ovi.dwPlatformId) //Not NT + { + SetLastError(NO_ERROR); + return true; + } + if (ec=DelayLoadDlls()) + { + TRACEF("DelayLoadDlls failed in _IsAdmin() with err x%X\n",ec); + SetLastError(ec); + return false; + } + + ASSERT(_OpenThreadToken && _OpenProcessToken && _AllocateAndInitializeSid && _EqualSid && _FreeSid); + HANDLE hToken; + if (_OpenThreadToken(GetCurrentThread(),TOKEN_QUERY,FALSE,&hToken) || _OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken)) + { + SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; + PSID psid=0; + if (_AllocateAndInitializeSid(&SystemSidAuthority,2,SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,&psid)) + { + if (_CheckTokenMembership) + { + if (!_CheckTokenMembership(0,psid,&isAdmin))isAdmin=false; + } + else + { + DWORD cbTokenGrps; + if (!_GetTokenInformation(hToken,TokenGroups,0,0,&cbTokenGrps)&&GetLastError()==ERROR_INSUFFICIENT_BUFFER) + { + TOKEN_GROUPS*ptg=0; + if (ptg=(TOKEN_GROUPS*)NSIS::MemAlloc(cbTokenGrps)) + { + if (_GetTokenInformation(hToken,TokenGroups,ptg,cbTokenGrps,&cbTokenGrps)) + { + for (UINT i=0; iGroupCount;i++) + { + if (_EqualSid(ptg->Groups[i].Sid,psid))isAdmin=true; + } + } + NSIS::MemFree(ptg); + } + } + } + _FreeSid(psid); + } + CloseHandle(hToken); + } + if (isAdmin) //UAC Admin with split token check + { + if (_SupportsUAC()) + { + TOKEN_ELEVATION_TYPE tet; + if (_GetElevationType(&tet) || tet==TokenElevationTypeLimited)isAdmin=false; + } + else SetLastError(NO_ERROR); + } + return FALSE != isAdmin; +} + + +LRESULT CALLBACK IPCSrvWndProc(HWND hwnd,UINT uMsg,WPARAM wp,LPARAM lp) +{ + switch(uMsg) + { + case WM_DESTROY: + PostQuitMessage(0); + break; + case WM_CLOSE: + return DestroyWindow(hwnd); + case WM_COPYDATA: + if (lp) + { + const COPYDATASTRUCT*pCDS=(COPYDATASTRUCT*)lp; + if (pCDS->dwData==CDI_SHEXEC && pCDS->lpData) + { + if ( pCDS->cbData < sizeof(IPC_SHEXEC) )break; + g.LastWaitExitCode=ERROR_INVALID_FUNCTION; + IPC_SHEXEC& ise=*((IPC_SHEXEC*)pCDS->lpData); + SetForegroundWindow(ise.hwnd); + DWORD ec=_Exec( + ise.hwnd, + &ise.buf[(DWORD_PTR)ise.strVerb], + &ise.buf[(DWORD_PTR)ise.strExec], + &ise.buf[(DWORD_PTR)ise.strParams], + &ise.buf[(DWORD_PTR)ise.strWorkDir], + ise.ShowMode,ise.Wait,ise.UseCreateProcess + ); + TRACEF("IPCSrvWndProc>IPC_SHEXEC>_ShExec=%d\n",ec); + return ec+1; + } + else if (pCDS->dwData==CDI_SYNCVAR && pCDS->lpData && pCDS->cbData>1) + { + IPC_SYNCVAR*pSV=(IPC_SYNCVAR*)pCDS->lpData; + if (pSV->VarId>=__INST_LAST)return 1+ERROR_INVALID_PARAMETER; + TRACEF("WM_COPYDATA: CDI_SYNCVAR:%d=%s|\n",pSV->VarId,&pSV->buf[0]); + lstrcpy(GetVar(pSV->VarId),&pSV->buf[0]); + return NO_ERROR+1; + } + else if (pCDS->dwData==CDI_STACKPUSH && pCDS->lpData && pCDS->cbData>=1) + { + TRACEF("WM_COPYDATA: CDI_STACKPUSH:%s|\n",pCDS->lpData); + return StackPush((NSISCH*)pCDS->lpData)+1; + } + } + break; + case IPC_GETEXITCODE: + return g.LastWaitExitCode; + case IPC_ELEVATEAGAIN: + TRACE("IPCSrvWndProc>IPC_ELEVATEAGAIN\n"); + return (g.ElevateAgain=true); + case IPC_GETSRVPID: + return GetCurrentProcessId(); + case IPC_GETSRVHWND: + return GetWindowLongPtr(hwnd,GWLP_USERDATA); + case IPC_EXECCODESEGMENT: + return 1+(g.pXParams ? ExecuteCodeSegment(g.pXParams,wp,(HWND)lp) : ERROR_INVALID_FUNCTION); + case IPC_GETOUTERPROCESSTOKEN: + if (_OpenProcessToken) + { + HANDLE hToken,hOutToken; + if (_OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hToken)) + { + TRACEF("IPC_GETOUTERPROCESSTOKEN: hToken=%X targetProcess=%X\n",hToken,g.hElevatedProcess); + if (DuplicateHandle(GetCurrentProcess(),hToken,g.hElevatedProcess,&hOutToken,lp,false,DUPLICATE_CLOSE_SOURCE)) + { + TRACEF("IPC_GETOUTERPROCESSTOKEN: %X(%X) > %X(%X)\n",hToken,-1,hOutToken,g.hElevatedProcess); + return (LRESULT)hOutToken; + } + } + } + return NULL; + +#ifdef UAC_HACK_FGWND1 + case IPC_HACKFINDRUNAS: //super ugly hack to get title of run as dialog + if (wp<200) + { + HWND hRA=GetLastActivePopup((HWND)lp); + TRACEF("IPC_HACKFINDRUNAS:%d %X %X\n",wp,lp,hRA); + if (hRA && hRA !=(HWND)lp ) return PostMessage((HWND)lp,WM_APP,0,(LONG_PTR)hRA); + Sleep(10);PostMessage(hwnd,uMsg,wp+1,lp); + } + break; +#endif + } + return DefWindowProc(hwnd,uMsg,wp,lp); +} + + +DWORD WINAPI IPCSrvThread(LPVOID lpParameter) +{ + CoInitialize(0); + const DWORD WStyle=WS_VISIBLE DBGONLY(|(WS_CAPTION)); + const int PosOffset=32700; + MSG msg; + WNDCLASS wc={0}; + wc.lpszClassName=GetIPCWndClass(); + wc.lpfnWndProc=IPCSrvWndProc; + wc.hInstance=g.hInstance; + if (!RegisterClass(&wc))goto dieLastErr; + if (!(g.hSrvIPC=CreateWindowEx(WS_EX_TOOLWINDOW DBGONLY(&~WS_EX_TOOLWINDOW), + GetIPCWndClass(), + DBGONLY(_T("Debug: NSIS.UAC")+)0, + WStyle, + -PosOffset DBGONLY(+PosOffset),-PosOffset DBGONLY(+PosOffset),DBGONLY(150+)1,DBGONLY(10+)1, + 0,0,wc.hInstance,0 + )))goto dieLastErr; + SetWindowLongPtr(g.hSrvIPC,GWLP_USERDATA,(LONG_PTR)lpParameter); + TRACEF("IPCSrv=%X server created...\n",g.hSrvIPC); + while (GetMessage(&msg,0,0,0)>0)DispatchMessage(&msg); + SetLastError(NO_ERROR); +dieLastErr: + CoUninitialize(); + return g.LastWaitExitCode=GetLastError(); +} + +DWORD InitIPC(HWND hwndNSIS,NSIS::extra_parameters*pXParams,UINT NSISStrLen) +{ + if (g.threadIPC)return NO_ERROR; + TRACEF("InitIPC StrSize=%u vs %u\n",NSIS::StrSize,NSISStrLen); + DWORD tid; + ASSERT(!g.pXParams && pXParams); + ASSERT(NSISStrLen>0 && NSISStrLen==NSIS::StrSize); + g.NSISStrLen=NSISStrLen; + g.pXParams=pXParams; + g.threadIPC=CreateThread(0,0,IPCSrvThread,hwndNSIS,0,&tid); + if (g.threadIPC) + { + while(!g.hSrvIPC && !g.LastWaitExitCode)Sleep(20); + return g.hSrvIPC ? NO_ERROR : g.LastWaitExitCode; + } + return GetLastError(); +} + +void StopIPCSrv() +{ + if (g.threadIPC) + { + TRACEF("StopIPCSrv h=%X \n",g.hSrvIPC); +#ifdef UAC_HACK_Clammerz + if ( GetSysVer()>=5 ) + { + //WINBUGFIX: This ugly thing supposedly solves the problem of messagebox'es in .OnInit appearing behind other windows in Vista + HWND hack=CreateWindowEx(WS_EX_TRANSPARENT|WS_EX_LAYERED,_T("Button"),NULL,NULL,0,0,0,0,NULL,NULL,NULL,0); + ShowWindow(hack,SW_SHOW); + SetForegroundWindow(hack); + DestroyWindow(hack); + } +#endif + PostMessage(g.hSrvIPC,WM_CLOSE,0,0); + WaitForSingleObject(g.threadIPC,INFINITE); + CloseHandle(g.threadIPC); + UnregisterClass(GetIPCWndClass(),g.hInstance);//DLL can be loaded more than once, so make sure RegisterClass doesn't fail + g.hSrvIPC=0; + g.threadIPC=0; + } +} + +#ifdef UAC_HACK_FGWND1 +LRESULT CALLBACK HackWndSubProc(HWND hwnd,UINT Msg,WPARAM wp,LPARAM lp) +{ + switch(Msg) + { + case WM_APP: + GetWindowText((HWND)lp,GetVar(0),NSIS::StrSize); + if (*GetVar(0))SendMessage(hwnd,WM_SETTEXT,0,(LONG_PTR)GetVar(0)); + break; + } + return DefWindowProc(hwnd,Msg,wp,lp); +} +#endif + +inline bool MustUseInternalRunAs() +{ +#ifdef BUILD_DBGSELECTELVMODE + TCHAR dbgb[MAX_PATH*4];wsprintf(dbgb,_T("%s.ini"),GetVar(VIDX_EXEPATH)); + static int dbg_answer=GetPrivateProfileInt(_T("UACDBG"),_T("MustUseInternalRunAs"),2,dbgb); + if (dbg_answer<2)return !!dbg_answer;WritePrivateProfileString(_T("UACDBG"),_T("MustUseInternalRunAs"),"",dbgb); + if (MessageBox(GetActiveWindow(),"MustUseInternalRunAs?",dbgb,MB_YESNO)==IDYES)return true; +#endif + return GetSysVer()>=6 && !SysElevationPresent(); +} + +DWORD ForkSelf(HWND hParent,DWORD&ForkExitCode,NSIS::extra_parameters*pXParams,UINT NSISStrLen) +{ + DWORD ec=ERROR_ACCESS_DENIED; + SHELLEXECUTEINFO sei={sizeof(sei)}; + //STARTUPINFO startInfo={sizeof(STARTUPINFO)}; + LPTSTR pszExePathBuf=0; + LPTSTR pszParamBuf=0; + LPTSTR p,pCL=GetCommandLine(); + UINT len; + const OSVerMaj=GetOSVerMaj(); +#ifdef UAC_HACK_FGWND1 + HWND hHack=0; +#endif + ASSERT(pXParams); + + //GetStartupInfo(&startInfo); + if (ec=InitIPC(hParent,pXParams,NSISStrLen))goto ret; + ASSERT(IsWindow(g.hSrvIPC)); + sei.hwnd=hParent; + sei.nShow=/*(startInfo.dwFlags&STARTF_USESHOWWINDOW) ? startInfo.wShowWindow :*/ SW_SHOWNORMAL; + sei.fMask=SEE_MASK_NOCLOSEPROCESS|SEE_MASK_NOZONECHECKS; + sei.lpVerb=_T("runas"); + p=FindExePathEnd(pCL); + len=p-pCL; + if (!p || !len) + { + ec=ERROR_FILE_NOT_FOUND; + goto ret; + } + for (;;) + { + NSIS::MemFree(pszExePathBuf); + if (!(pszExePathBuf=(LPTSTR)NSIS::MemAlloc((++len)*sizeof(TCHAR))))goto dieOOM; + if ( GetModuleFileName(0,pszExePathBuf,len) < len )break; //FUCKO: what if GetModuleFileName returns 0? + len+=MAX_PATH; + } + sei.lpFile=pszExePathBuf; + len=lstrlen(p); + len+=20;//space for "/UAC:xxxxxx /NCRC\0" + if (!(pszParamBuf=(LPTSTR)NSIS::MemAlloc(len*sizeof(TCHAR))))goto dieOOM; + wsprintf(pszParamBuf,_T("/UAC:%X /NCRC%s"),g.hSrvIPC,p);//NOTE: The argument parser depends on our special flag appearing first + sei.lpParameters=pszParamBuf; + + + if (OSVerMaj==5) + { + bool hasseclogon=SysNT5IsSecondaryLogonSvcRunning(); + TRACEF("SysNT5IsSecondaryLogonSvcRunning=%d\n",hasseclogon); + if (!hasseclogon) + { + ec=ERROR_SERVICE_NOT_ACTIVE; + goto ret; + } + } + + + + +#ifdef UAC_HACK_FGWND1 + if ( OSVerMaj>=5 && !sei.hwnd ) + { + //sei.nShow=SW_SHOW;//forced, do we HAVE to do this? + hHack=CreateWindowEx(WS_EX_TRANSPARENT|WS_EX_LAYERED|WS_EX_TOOLWINDOW|WS_EX_APPWINDOW,_T("Button"),GetVar(VIDX_EXEFILENAME),0|WS_MAXIMIZE,0,0,0,0,NULL,NULL,NULL,0); + + SetWindowLongPtr(hHack,GWLP_WNDPROC,(LONG_PTR)HackWndSubProc); + if (GetSysVer()<6 || MustUseInternalRunAs()) + PostMessage(g.hSrvIPC,IPC_HACKFINDRUNAS,0,(LONG_PTR)hHack); + else + SetWindowLongPtr(hHack,GWL_EXSTYLE,GetWindowLongPtr(hHack,GWL_EXSTYLE)&~WS_EX_APPWINDOW);//kill taskbar btn on vista + HICON hIcon=(HICON)LoadImage(GetModuleHandle(0),MAKEINTRESOURCE(103),IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_SHARED); + SendMessage(hHack,WM_SETICON,ICON_BIG,(LONG_PTR)hIcon); + ShowWindow(hHack,SW_SHOW); + SetForegroundWindow(hHack); + sei.hwnd=hHack; + } +#endif + + if (hParent)SetForegroundWindow(hParent);//try to force taskbar button active (for RunElevatedAndProcessMessages, really important on Vista) + +#ifdef FEAT_CUSTOMRUNASDLG + if (MustUseInternalRunAs()) + { + ec=MyRunAs(g.hInstance,sei); + } + else +#endif + { + if (GetSysVer()>=6) + { + ////////sei.nShow=SW_SHOW; + //if ( _SupportsUAC() )sei.hwnd=0; //Vista does not like it when we provide a HWND + //if (_AllowSetForegroundWindow) _AllowSetForegroundWindow(ASFW_ANY);//TODO: is GrantClientWindowInput() enough? + } +#ifdef FEAT_MSRUNASDLGMODHACK + void* hook=MSRunAsDlgMod_Init(); +#endif + TRACEF("ForkSelf:calling ShExec:app=%s|params=%s|vrb=%s|hwnd=%X\n",sei.lpFile,sei.lpParameters,sei.lpVerb,sei.hwnd); + ec=(ShellExecuteEx(&sei)?NO_ERROR:GetLastError()); + TRACEF("ForkSelf: ShExec->Runas returned %d hInstApp=%d\n",ec,sei.hInstApp); +#ifdef FEAT_MSRUNASDLGMODHACK + MSRunAsDlgMod_Unload(hook); +#endif + } +#ifdef UAC_HACK_FGWND1 + DestroyWindow(hHack); +#endif + if (ec)goto ret; + TRACEF("ForkSelf: waiting for process %X (%s|%s|%s)sei.hwnd=%X\n",(sei.hProcess),sei.lpFile,sei.lpParameters,sei.lpVerb,sei.hwnd); + ASSERT(sei.hProcess); + ASSERT(NO_ERROR==ec); + ShowWindow(g.hSrvIPC,SW_HIDE); + + g.hElevatedProcess=sei.hProcess; + + if (!IsWindow(sei.hwnd)) + { + DWORD w=WaitForSingleObject(sei.hProcess,INFINITE); + if (w==WAIT_OBJECT_0) + VERIFY(GetExitCodeProcess(sei.hProcess,&ForkExitCode)); + else + { + ec=GetLastError(); + TRACEF("ForkSelf:WaitForSingleObject failed ec=%d w=%d\n",ec,w);ASSERT(!"ForkSelf:WaitForSingleObject"); + } + } + else + { + bool abortWait=false; + const DWORD waitCount=1; + const HANDLE handles[waitCount]={sei.hProcess}; + do + { + DWORD w=MsgWaitForMultipleObjects(waitCount,handles,false,INFINITE,QS_ALLEVENTS|QS_ALLINPUT); + switch(w) + { + case WAIT_OBJECT_0: + VERIFY(GetExitCodeProcess(sei.hProcess,&ForkExitCode)); + abortWait=true; + break; + case WAIT_OBJECT_0+waitCount: + { + const HWND hwnd=sei.hwnd; + MSG msg; + while( !ec && PeekMessage(&msg,hwnd,0,0,PM_REMOVE) ) + { + if (msg.message==WM_QUIT) + { + ASSERT(0); + ec=ERROR_CANCELLED; + break; + } + if (!IsDialogMessage(hwnd,&msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + break; + default: + abortWait=true; + ec=GetLastError(); + TRACEF("ForkSelf:MsgWaitForMultipleObjects failed, ec=%u w=%u\n",ec,w); + } + } while( NO_ERROR==ec && !abortWait ); + } + + TRACEF("ForkSelf: wait complete, ec=%d forkexitcode=%u\n",ec,ForkExitCode); + goto ret; +dieOOM: + ec=ERROR_OUTOFMEMORY; +ret: + StopIPCSrv(); + CloseHandle(sei.hProcess); + NSIS::MemFree(pszExePathBuf); + NSIS::MemFree(pszParamBuf); + return ec; +} + +bool GetIPCSrvWndFromParams(HWND&hwndOut) +{ + LPTSTR p=FindExePathEnd(GetCommandLine()); + while(p && *p==' ')p=CharNext(p);TRACEF("GetIPCSrvWndFromParams:%s|\n",p); + if (p && *p++=='/'&&*p++=='U'&&*p++=='A'&&*p++=='C'&&*p++==':') + { + hwndOut=(HWND)StrToUInt(p,true); + return !!IsWindow(hwndOut); + } + return false; +} + + +/*** RunElevated +Return: r0: Windows error code (0 on success, 1223 if user aborted elevation dialog, anything else should be treated as a fatal error) + r1: If r0==0, r1 is: + 0 if UAC is not supported by the OS, + 1 if UAC was used to elevate and the current process should act like a wrapper (Call Quit in .OnInit without any further processing), + 2 if the process is (already?) running @ HighIL (Member of admin group on other systems), + 3 if you should call RunElevated again (This can happen if a user without admin priv. is used in the runas dialog), + r2: If r0==0 && r1==1: r2 is the ExitCode of the elevated fork process (The NSIS errlvl is also set to the ExitCode) + r3: If r0==0: r3 is 1 if the user is a member of the admin group or 0 otherwise +*/ +EXPORTNSISFUNC RunElevated(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + + BYTE UACMode=0; + bool UserIsAdmin=false; + DWORD ec=ERROR_ACCESS_DENIED,ForkExitCode; + TOKEN_ELEVATION_TYPE tet; + + UserIsAdmin=_IsAdmin(); + TRACEF("RunElevated:Init: IsAdmin=%d\n",UserIsAdmin); +#ifdef BUILD_XPTEST + if (!UserIsAdmin)goto DbgXPAsUAC;//Skip UAC detection for special debug builds and force a call to runas on +Return: windows error code in r0, 0 on success +*/ +EXPORTNSISFUNC Exec(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + HandleExecExport(true,false,hwndNSIS,StrSize,Vars,StackTop,XParams); + NSISFUNCEND(); +} + +/*** ExecWait +Notes: + ¤ ErrorFlag is also set on error +STACK: +Return: + r0: windows error code, 0 on success + r1: exitcode of new process +*/ +EXPORTNSISFUNC ExecWait(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + HandleExecExport(true,true,hwndNSIS,StrSize,Vars,StackTop,XParams); + NSISFUNCEND(); +} + +/*** ShellExec +Notes: + ¤ ErrorFlag is also set on error +STACK: +Return: windows error code in r0, 0 on success +*/ +EXPORTNSISFUNC ShellExec(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + HandleExecExport(false,false,hwndNSIS,StrSize,Vars,StackTop,XParams); + NSISFUNCEND(); +} + +/*** ShellExecWait +Notes: + ¤ ErrorFlag is also set on error +STACK: +Return: + r0: windows error code, 0 on success + r1: exitcode of new process +*/ +EXPORTNSISFUNC ShellExecWait(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + HandleExecExport(false,true,hwndNSIS,StrSize,Vars,StackTop,XParams); + NSISFUNCEND(); +} + + +/*** GetElevationType +Notes: + TokenElevationTypeDefault=1 :User is not using a split token (UAC disabled) + TokenElevationTypeFull=2 :UAC enabled, the process is elevated + TokenElevationTypeLimited=3 :UAC enabled, the process is not elevated +Return: r0: (TOKEN_ELEVATION_TYPE)TokenType, The error flag is set if the function fails and r0==0 +*/ +EXPORTNSISFUNC GetElevationType(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + TOKEN_ELEVATION_TYPE tet=(TOKEN_ELEVATION_TYPE)NULL; //Default to invalid value + if (MaintainDllSelfRef() || /*!_SupportsUAC() ||*/ _GetElevationType(&tet)) SetErrorFlag(XParams); + SetVarUINT(INST_0,tet); + NSISFUNCEND(); +} + + + +/*** SupportsUAC +Notes: Check if the OS supports UAC (And the user has UAC turned on) +Return: r0: (BOOL)Result +*/ +EXPORTNSISFUNC SupportsUAC(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + BOOL present=false; + MaintainDllSelfRef(); + if (_SupportsUAC())present=true; + SetVarUINT(INST_0,present); + NSISFUNCEND(); +} + + +/*** IsAdmin +Return: r0: (BOOL)Result +*/ +EXPORTNSISFUNC IsAdmin(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + bool Admin=false; + DWORD ec; + if ( !(ec=MaintainDllSelfRef()) ) + { + Admin=_IsAdmin(); + if ( ec=GetLastError() ) + { + TRACEF("IsAdmin failed with %d\n",ec); + SetErrorFlag(XParams); + Admin=false; + } + } + SetVarUINT(INST_0,Admin); + NSISFUNCEND(); +} + + + +/*** ExecCodeSegment +Notes: Sets error flag on error + There is currently no way to transfer state to/from the executed code segment! + If you use instructions that alter the UI or the stack/variables in the code segment (StrCpy,Push/Pop/Exch,DetailPrint,HideWindow etc.) they will affect the hidden wrapper installer and not "your" installer instance! +*/ +EXPORTNSISFUNC ExecCodeSegment(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + + DWORD ec; + if (!(ec=DllSelfAddRef())) //force AddRef since our plugin could be called inside the executed code segment! + { + ec=ERROR_INVALID_PARAMETER; + stack_t* pSI=StackPop(); + if (pSI) + { + BOOL badCh; + UINT pos=StrToUInt(pSI->text,false,&badCh); + TRACEF("ExecCodeSegment %d (%s) badinput=%d\n",pos-1,pSI->text,badCh); + if (!badCh && pos--) + { + if (!g.UseIPC) + ec=NSIS::ExecuteCodeSegment(XParams,pos); + else + { + SyncVars(hwndNSIS); + DWORD_PTR MsgRet; + AllowOuterInstanceWindowFocus(); + if (!(ec=SendIPCMsg(IPC_EXECCODESEGMENT,pos,0,MsgRet,INFINITE)))ec=MsgRet-1; + } + } + StackFreeItem(pSI); + } + } + if (ec)SetErrorFlag(XParams); + + NSISFUNCEND(); +} + + + +/*** StackPush */ +EXPORTNSISFUNC StackPush(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + + DWORD ec; + if (!(ec=DllSelfAddRef()) && g.UseIPC) + { + stack_t* pSI=StackPop(); + ec=ERROR_INVALID_PARAMETER; + if (pSI) + { + DWORD_PTR MsgRet; + COPYDATASTRUCT cds={CDI_STACKPUSH,(lstrlen(pSI->text)+1)*sizeof(NSISCH),pSI->text}; + if (!(ec=SendIPCMsg(WM_COPYDATA,(WPARAM)hwndNSIS,(LPARAM)&cds,MsgRet,5000 )))ec=MsgRet-1; + StackFreeItem(pSI); + } + } + if (ec)SetErrorFlag(XParams); + + NSISFUNCEND(); +} + + + +/*** GetOuterHwnd */ +EXPORTNSISFUNC GetOuterHwnd(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + MaintainDllSelfRef(); + DWORD_PTR MsgRet;HWND hSrvIPC; + if (!GetIPCSrvWndFromParams(hSrvIPC)||!IsWindow(hSrvIPC)||SendIPCMsg(IPC_GETSRVHWND,0,0,MsgRet,IPCTOUT_DEF,hSrvIPC))MsgRet=0; + SetVarUINT(INST_0,MsgRet); + NSISFUNCEND(); +} + + +DWORD SetPrivilege(LPCSTR PrivName,bool Enable) +{ + DWORD r=NO_ERROR; + HANDLE hToken=NULL; + TOKEN_PRIVILEGES TokenPrivs; + if (!LookupPrivilegeValueA(NULL,PrivName,&TokenPrivs.Privileges[0].Luid))goto dieGLE; + if (!_OpenProcessToken(GetCurrentProcess (),TOKEN_ADJUST_PRIVILEGES,&hToken))goto dieGLE; + TokenPrivs.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0 ; + TokenPrivs.PrivilegeCount=1; + if (AdjustTokenPrivileges(hToken,FALSE,&TokenPrivs,0,NULL,NULL))goto ret; +dieGLE: + r=GetLastError(); +ret: + CloseHandle(hToken); + return r; +} + + +#include +/*** GetShellFolderPath */ +EXPORTNSISFUNC GetShellFolderPath(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + /* + WINBUG: + For some reason, even with debug priv. enabled, a call to OpenProcessToken(TOKEN_READ|TOKEN_IMPERSONATE) + will fail, even if we have a PROCESS_ALL_ACCESS handle on XP when running as a member of the Power Users Group. + So we have to ask the outer process to give us the handle. + */ + + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + MaintainDllSelfRef(); + + const unsigned TokenAccessRights=TOKEN_READ|TOKEN_IMPERSONATE; + unsigned clsidFolder; + HWND hSrvIPC; + HANDLE hToken=NULL,hOuterProcess=NULL; + DWORD SrvPID; + HRESULT hr; + FARPROC pfnSHGetFolderPath; + LPTSTR buf=GetVar(INST_0); + stack_t*pssCLSID=StackPop(); + stack_t*pssFallback=NULL; + BOOL ConvBadCh; + if (!pssCLSID || !(pssFallback=StackPop())) goto fail; + clsidFolder=StrToUInt(pssCLSID->text,false,&ConvBadCh); + if (ConvBadCh)goto fail; + TRACEF("GetShellFolderPath HasIPCServer=%X param=%s>%X fallback=%s|\n",HasIPCServer(),pssCLSID->text,clsidFolder,pssFallback->text); + + pfnSHGetFolderPath=GetProcAddress(GetModuleHandle(_T("SHELL32")),"SHGetFolderPath"__DLD_FUNCSUFFIX); + if (!pfnSHGetFolderPath)goto fail; + + if (GetIPCSrvWndFromParams(hSrvIPC) && 0 != GetWindowThreadProcessId(hSrvIPC,&SrvPID)) + { + hOuterProcess=OpenProcess(PROCESS_QUERY_INFORMATION,false,SrvPID); + if (hOuterProcess) + { + BOOL bOk=OpenProcessToken(hOuterProcess,TokenAccessRights,&hToken); + CloseHandle(hOuterProcess); + if (bOk)goto gotToken; + + } +/* SetPrivilege(SE_DEBUG_NAME,true); + hOuterProcess=OpenProcess(PROCESS_DUP_HANDLE,false,SrvPID); + SetPrivilege(SE_DEBUG_NAME,false); + if (!hOuterProcess)goto fail; + TRACEF("hOuterProcess=%X\n",hOuterProcess); +*/ SendIPCMsg(IPC_GETOUTERPROCESSTOKEN,0,TokenAccessRights,(DWORD_PTR&)hToken,IPCTOUT_DEF,hSrvIPC); + TRACEF("IPC_GETOUTERPROCESSTOKEN=%X\n",hToken);//*/ + } +gotToken: + if (HasIPCServer() && !hToken)goto fail; + + hr=((HRESULT(WINAPI*)(HWND,int,HANDLE,DWORD,LPTSTR))pfnSHGetFolderPath)(hwndNSIS,clsidFolder,hToken,SHGFP_TYPE_CURRENT,buf); + TRACEF("SHGetFolderPath hr=%X with token=%X, clsidFolder=%X|%s\n",hr,hToken,clsidFolder,buf); + if (FAILED(hr)) goto fail; else goto ret; +fail: + TRACEF("GetShellFolderPath GLE=%X\n",GetLastError()); + lstrcpy(buf,pssFallback->text); + TRACEF("%s|%s\n",buf,pssFallback->text); +ret: +// CloseHandle(hOuterProcess); + CloseHandle(hToken); + StackFreeItem(pssFallback); + StackFreeItem(pssCLSID); + NSISFUNCEND(); +} + + + +/*** GetOuterPID * / +EXPORTNSISFUNC GetOuterPID(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams) +{ + NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams); + MaintainDllSelfRef(); + DWORD_PTR Ret=0; + HWND hSrvIPC; + if (GetIPCSrvWndFromParams(hSrvIPC)) + if (0==GetWindowThreadProcessId(hSrvIPC,&Ret))Ret=0; + SetVarUINT(INST_0,Ret); + NSISFUNCEND(); +}//*/ + + + +/*** Unload +Notes: Call in .OnInstFailed AND .OnInstSuccess ! +*/ +EXPORTNSISFUNC Unload(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop) +{ + NSISFUNCSTART4(hwndNSIS,StrSize,Vars,StackTop); + if (!MaintainDllSelfRef())_Unload(); else ASSERT(!"MaintainDllSelfRef failed in Unload!"); + NSISFUNCEND(); +} + + + +#ifdef _DEBUG +BOOL WINAPI DllMain(HINSTANCE hInst,DWORD Event,LPVOID lpReserved) +#else +extern "C" BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst,ULONG Event,LPVOID lpReserved) +#endif +{ + if (Event==DLL_PROCESS_ATTACH) + { + TRACEF("************************************ DllMain %u\n",GetCurrentProcessId()); + ASSERT(!_OpenProcessToken && !_EqualSid); + g.hInstance=hInst; + } +// DBGONLY( if (Event==DLL_PROCESS_DETACH){ASSERT(g.DllRef==0);}TRACE("DLL_PROCESS_DETACH\n"); );//Make sure we unloaded so we don't lock $pluginsdir + return TRUE; +} + + diff --git a/admin/win/nsis_uac/uac.h b/admin/win/nsis_uac/uac.h new file mode 100755 index 000000000..8e6e396e3 --- /dev/null +++ b/admin/win/nsis_uac/uac.h @@ -0,0 +1,169 @@ +//Copyright (C) 2007 Anders Kjersem. Licensed under the zlib/libpng license, see License.txt for details. +#pragma once +/** /#define BUILD_DBGRELEASE // Include simple debug output in release version */ +/** /#define BUILD_DBGSELECTELVMODE //Test MyRunAs*/ + +/** /#define UNICODE // Unicode build */ +/**/#define FEAT_CUSTOMRUNASDLG // Include custom runas dialog */ +/**/#define FEAT_CUSTOMRUNASDLG_TRANSLATE //*/ +/**/#define FEAT_MSRUNASDLGMODHACK // Default to other user radio button */ + + +#if !defined(APSTUDIO_INVOKED) && !defined(RC_INVOKED) + +#if (defined(_MSC_VER) && !defined(_DEBUG)) + #pragma comment(linker,"/opt:nowin98") + #pragma comment(linker,"/ignore:4078") + #pragma comment(linker,"/merge:.rdata=.text") + + //#pragma intrinsic(memset) //http://www.codeguru.com/forum/showthread.php?t=371491&page=2&pp=15 | http://www.ddj.com/windows/184416623 +#endif + +#if defined(UNICODE) && !defined(_UNICODE) +#define _UNICODE +#endif +#ifdef _UNICODE +#define TFUNCSUFFIX W +#else +#define TFUNCSUFFIX A +#endif +#define _PCJOIN(a,b) a##b +#define PCJOIN(a,b) _PCJOIN(a,b) + + +#define _WIN32_WINNT 0x0501 +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include "NSISUtil.h" + +#ifndef SEE_MASK_NOZONECHECKS +#define SEE_MASK_NOZONECHECKS 0x00800000 +#endif + +#define COUNTOF(___c) ( sizeof(___c)/sizeof(___c[0]) ) +#ifndef ARRAYSIZE +#define ARRAYSIZE COUNTOF +#endif +#define FORCEINLINE __forceinline + +#if _MSC_VER >= 1400 +extern void* __cdecl memset(void*mem,int c,size_t len); +#endif + +FORCEINLINE LRESULT MySndDlgItemMsg(HWND hDlg,int id,UINT Msg,WPARAM wp=0,LPARAM lp=0) {return SendMessage(GetDlgItem(hDlg,id),Msg,wp,lp);} +#ifndef UAC_NOCUSTOMIMPLEMENTATIONS +FORCEINLINE HANDLE WINAPI GetCurrentProcess(){return ((HANDLE)(-1));} +FORCEINLINE HANDLE WINAPI GetCurrentThread(){return ((HANDLE)(-2));} + +#define MyTStrLen lstrlen + +#undef lstrcpy +#define lstrcpy MyTStrCpy +FORCEINLINE LPTSTR MyTStrCpy(LPTSTR s1,LPCTSTR s2) {return PCJOIN(lstr,PCJOIN(cpyn,TFUNCSUFFIX))(s1,s2,0x7FFFFFFF);} + +#undef lstrcat +#define lstrcat MyTStrCat +LPTSTR MyTStrCat(LPTSTR s1,LPCTSTR s2) +#ifdef UAC_INITIMPORTS +{return s1?MyTStrCpy(&s1[MyTStrLen(s1)],s2):NULL;} +#else +; +#endif //UAC_INITIMPORTS + +#endif //UAC_NOCUSTOMIMPLEMENTATIONS + + +//DelayLoaded functions: +typedef BOOL (WINAPI*ALLOWSETFOREGROUNDWINDOW)(DWORD dwProcessId); +typedef BOOL (WINAPI*OPENPROCESSTOKEN)(HANDLE ProcessHandle,DWORD DesiredAccess,PHANDLE TokenHandle); +typedef BOOL (WINAPI*OPENTHREADTOKEN)(HANDLE ThreadHandle,DWORD DesiredAccess,BOOL OpenAsSelf,PHANDLE TokenHandle); +typedef BOOL (WINAPI*GETTOKENINFORMATION)(HANDLE hToken,TOKEN_INFORMATION_CLASS TokInfoClass,LPVOID TokInfo,DWORD TokInfoLenh,PDWORD RetLen); +typedef BOOL (WINAPI*ALLOCATEANDINITIALIZESID)(PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,BYTE nSubAuthorityCount,DWORD sa0,DWORD sa1,DWORD sa2,DWORD sa3,DWORD sa4,DWORD sa5,DWORD sa6,DWORD sa7,PSID*pSid); +typedef PVOID (WINAPI*FREESID)(PSID pSid); +typedef BOOL (WINAPI*EQUALSID)(PSID pSid1,PSID pSid2); +typedef BOOL (WINAPI*CHECKTOKENMEMBERSHIP)(HANDLE TokenHandle,PSID SidToCheck,PBOOL IsMember); +#ifdef FEAT_CUSTOMRUNASDLG +typedef BOOL (WINAPI*GETUSERNAME)(LPTSTR lpBuffer,LPDWORD nSize); +typedef BOOL (WINAPI*CREATEPROCESSWITHLOGONW)(LPCWSTR lpUsername,LPCWSTR lpDomain,LPCWSTR lpPassword,DWORD dwLogonFlags,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,DWORD dwCreationFlags,LPVOID pEnv,LPCWSTR WorkDir,LPSTARTUPINFOW pSI,LPPROCESS_INFORMATION pPI); +#define SECURITY_WIN32 +#include //NameSamCompatible +typedef BOOLEAN (WINAPI*GETUSERNAMEEX)(EXTENDED_NAME_FORMAT NameFormat,LPTSTR lpNameBuffer,PULONG nSize); +#endif +#ifdef UAC_INITIMPORTS +ALLOWSETFOREGROUNDWINDOW _AllowSetForegroundWindow=0; +OPENPROCESSTOKEN _OpenProcessToken=0; +OPENTHREADTOKEN _OpenThreadToken=0; +GETTOKENINFORMATION _GetTokenInformation=0; +ALLOCATEANDINITIALIZESID _AllocateAndInitializeSid=0; +FREESID _FreeSid=0; +EQUALSID _EqualSid=0; +CHECKTOKENMEMBERSHIP _CheckTokenMembership=0; +#ifdef FEAT_CUSTOMRUNASDLG +GETUSERNAME _GetUserName=0; +GETUSERNAMEEX _GetUserNameEx=0; +CREATEPROCESSWITHLOGONW _CreateProcessWithLogonW=0; +#endif +#else +#ifdef FEAT_CUSTOMRUNASDLG +extern GETUSERNAME _GetUserName; +extern GETUSERNAMEEX _GetUserNameEx; +extern CREATEPROCESSWITHLOGONW _CreateProcessWithLogonW; +#endif +#endif /* UAC_INITIMPORTS */ + + +extern DWORD DelayLoadDlls(); +#ifdef FEAT_CUSTOMRUNASDLG +extern DWORD MyRunAs(HINSTANCE hInstDll,SHELLEXECUTEINFO&sei); +#endif + +#if !defined(NTDDI_VISTA) || defined(BUILD_OLDSDK) +//#if !defined(NTDDI_VERSION) || (NTDDI_VERSION < 0x06000000) || !defined(NTDDI_VISTA) +//#if !defined(TOKEN_ELEVATION_TYPE) || defined(BUILD_OLDSDK) +enum TOKEN_ELEVATION_TYPE { + TokenElevationTypeDefault = 1, + TokenElevationTypeFull, + TokenElevationTypeLimited +}; +enum _TOKEN_INFORMATION_CLASS___VISTA { + TokenElevationType = (TokenOrigin+1), + TokenLinkedToken, + TokenElevation, + TokenHasRestrictions, + TokenAccessInformation, + TokenVirtualizationAllowed, + TokenVirtualizationEnabled, + TokenIntegrityLevel, + TokenUIAccess, + TokenMandatoryPolicy, + TokenLogonSid, +}; +#endif + + +#if defined(_DEBUG) || defined(BUILD_DBGRELEASE) +//Simple debug helpers: +#define BUILD_DBG +/** /#define BUILD_XPTEST //Pretend UAC exists and "elevate" with NT runas */ +#define DBG_RESETDBGVIEW() do{HWND hDbgView=FindWindowA("dbgviewClass",0);PostMessage(hDbgView,WM_COMMAND,40020,0);if(0)SetForegroundWindow(hDbgView);}while(0) +#define _pp_MakeStr_(x) #x +#define pp_MakeStr(x) _pp_MakeStr_(x) +#define TRACE OutputDebugStringA +#define DBGONLY(_x) _x +#ifndef ASSERT +#define ASSERT(_x) do{if(!(_x)){MessageBoxA(GetActiveWindow(),#_x##"\n\n"##__FILE__##":"## pp_MakeStr(__LINE__),"SimpleAssert",0);/*TRACE(#_x##"\n"##__FILE__##":" pp_MakeStr(__LINE__)"\n");*/}}while(0) +#endif +#define VERIFY(_x) ASSERT(_x) +static void TRACEF(const char*fmt,...) {va_list a;va_start(a,fmt);static TCHAR b[1024*4];if (sizeof(TCHAR)!=sizeof(char)){static TCHAR fmtBuf[COUNTOF(b)];VERIFY(wsprintf(fmtBuf,_T("%hs"),fmt)