From f7316086c0cfc1ef00c1c411bc6fb7572d9d7e29 Mon Sep 17 00:00:00 2001 From: Steven Robertson Date: Thu, 4 Nov 2010 22:42:06 +0000 Subject: [PATCH 1/2] Updating the Windows installer script. --- admin/win/RELEASE_NOTES.txt | 1 + admin/win/installer.ico | Bin 0 -> 2998 bytes admin/win/nsis_uac/History.txt | 102 ++ admin/win/nsis_uac/License.txt | 14 + admin/win/nsis_uac/NSISUtil.h | 149 ++ admin/win/nsis_uac/Release/A/UAC.dll | Bin 0 -> 17408 bytes admin/win/nsis_uac/Release/U/UAC.dll | Bin 0 -> 18432 bytes admin/win/nsis_uac/RunAs.cpp | 277 +++ admin/win/nsis_uac/UAC Readme.html | 222 +++ admin/win/nsis_uac/UAC.nsh | 191 +++ admin/win/nsis_uac/UAC_AdminOnly.nsi | 62 + admin/win/nsis_uac/UAC_AllowLUA.nsi | 45 + .../nsis_uac/UAC_GetUserShellFolderPath.nsi | 30 + ...AC_RealWorldFullyLoadedDualModeExample.nsi | 242 +++ admin/win/nsis_uac/UAC_Uninstaller.nsi | 49 + admin/win/nsis_uac/resource.h | 24 + admin/win/nsis_uac/resource.rc | 109 ++ admin/win/nsis_uac/uac.cpp | 1518 +++++++++++++++++ admin/win/nsis_uac/uac.h | 169 ++ admin/win/page_header.bmp | Bin 0 -> 25818 bytes admin/win/revision.txt | 1 + admin/win/tomahawk.ini | 21 + admin/win/tomahawk.nsi | 672 ++++++-- admin/win/welcome.bmp | Bin 0 -> 154542 bytes 24 files changed, 3774 insertions(+), 124 deletions(-) create mode 100755 admin/win/RELEASE_NOTES.txt create mode 100755 admin/win/installer.ico create mode 100755 admin/win/nsis_uac/History.txt create mode 100755 admin/win/nsis_uac/License.txt create mode 100755 admin/win/nsis_uac/NSISUtil.h create mode 100755 admin/win/nsis_uac/Release/A/UAC.dll create mode 100755 admin/win/nsis_uac/Release/U/UAC.dll create mode 100755 admin/win/nsis_uac/RunAs.cpp create mode 100755 admin/win/nsis_uac/UAC Readme.html create mode 100755 admin/win/nsis_uac/UAC.nsh create mode 100755 admin/win/nsis_uac/UAC_AdminOnly.nsi create mode 100755 admin/win/nsis_uac/UAC_AllowLUA.nsi create mode 100755 admin/win/nsis_uac/UAC_GetUserShellFolderPath.nsi create mode 100755 admin/win/nsis_uac/UAC_RealWorldFullyLoadedDualModeExample.nsi create mode 100755 admin/win/nsis_uac/UAC_Uninstaller.nsi create mode 100755 admin/win/nsis_uac/resource.h create mode 100755 admin/win/nsis_uac/resource.rc create mode 100755 admin/win/nsis_uac/uac.cpp create mode 100755 admin/win/nsis_uac/uac.h create mode 100755 admin/win/page_header.bmp create mode 100755 admin/win/revision.txt create mode 100755 admin/win/tomahawk.ini create mode 100755 admin/win/welcome.bmp 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 0000000000000000000000000000000000000000..94753ac296389ae5b90e56608a5fd1882692985f GIT binary patch literal 2998 zcmc)MKWH0g9LDjV6N8TqPFH90BGc8{op$J8YpEB%MkvWdDv$`envn4WpSL6%MXQ^LNCuEYnNE+KOLGOMmO~`pV9URzm zD%EP0qYjk$CrarvDx3aD?}B1w`)B58Wj2pq2A^bnPb9x(9~FZS@>?5eE9rkYEZPQ; zC#_80KKvv-OKNJ7oCkkZeQHca7_lbVapldmq0wze`;HdCN&+d1dR*7LU0LEHNN$lkEB*?#-p zbvB#l_ElQ4*|cpFnZguI+l;Jt8im}#+UGUd;-535w*frDt^rC!?<-R<8%0R{31SrAGbht)x;m;OZYsVl~$|V*yshS zD-Ykm*YP!c1<&G)S)e+91IpAKb)C9MjZnue(BF5ND}lV4tP1CG;ff08Tp zC#BofS2V@snhL}FdSQl&8J}0eb%R__XQ*`k3NEh<5Uw~>7``{28KGzU7guI_dORn% z1o>pB+~z%?^P4A6wkeyNo0FkD7+L4JXMHe~2lEg$`D_4&b8}m!e;E8pR^Ctr^ lCLe%txdGhf=zR40^d5?NRR+r&UY{Q5ep2}P`k()w@;93z)Y + + +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 0000000000000000000000000000000000000000..edf21305a459975db7d2f35056acda77e48bdfa8 GIT binary patch literal 17408 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..94dc7115489bc82b2e0af7da8baf95ff1cbd3fde GIT binary patch literal 18432 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//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"),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 literal 0 HcmV?d00001 diff --git a/admin/win/revision.txt b/admin/win/revision.txt new file mode 100755 index 000000000..368f89cee --- /dev/null +++ b/admin/win/revision.txt @@ -0,0 +1 @@ +28 \ No newline at end of file diff --git a/admin/win/tomahawk.ini b/admin/win/tomahawk.ini new file mode 100755 index 000000000..be3933a95 --- /dev/null +++ b/admin/win/tomahawk.ini @@ -0,0 +1,21 @@ +[Settings] +NumFields=3 +[Field 1] +Type=Label +Left=0 +Right=-1 +Top=0 +Bottom=24 +[Field 2] +Type=RadioButton +Left=30 +Right=-1 +Top=50 +Bottom=58 +State=1 +[Field 3] +Type=RadioButton +Left=30 +Right=-1 +Top=70 +Bottom=78 \ No newline at end of file diff --git a/admin/win/tomahawk.nsi b/admin/win/tomahawk.nsi index 0012132a3..d74b1b51c 100755 --- a/admin/win/tomahawk.nsi +++ b/admin/win/tomahawk.nsi @@ -1,124 +1,548 @@ -; assuming the script is in ROOT/admin/win/ -!define ROOTDIR "../.." - -!include "MUI2.nsh" - -Name "Tomahawk" -!define MUI_NAME "Tomahawk" -!define MUI_PRODUCT "Tomahawk" -!define MUI_FILE "Tomahawk" -!define MUI_VERSION "Alpha" -!define MUI_BRANDINGTEXT "Tomahawk-Player Alpha Test" -CRCCheck On - - - -OutFile "tomahawk-setup-alpha.exe" -;ShowInstDetails "nevershow" -ShowUninstDetails "nevershow" -;SetCompressor "bzip2" - -!define MUI_ICON "..\..\data\icons\tomahawk.ico" -!define MUI_UNICON "..\..\data\icons\tomahawk.ico" -;!define MUI_SPECIALBITMAP "Bitmap.bmp" - - -InstallDir "$PROGRAMFILES\${MUI_PRODUCT}" - -;-------------------------------- -;Modern UI Configuration -!define MUI_WELCOMEPAGE_TEXT "This is an Alpha release, and is still buggy.$\n$\nPlease join #tomahawk-player on irc.freenode.net" -!insertmacro MUI_PAGE_WELCOME - -!insertmacro MUI_PAGE_LICENSE "${ROOTDIR}\LICENSE.txt" -;;!insertmacro MUI_PAGE_COMPONENTS -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES - -!define MUI_FINISHPAGE_RUN "$INSTDIR\tomahawk.exe" -!insertmacro MUI_PAGE_FINISH - -!insertmacro MUI_LANGUAGE "English" - -;Modern UI System -;!insertmacro MUI_SYSTEM - -LicenseData "${ROOTDIR}\LICENSE.txt" - -Section "install" - -;Add files -SetOutPath "$INSTDIR" - -;Path to our DLL cache -!define DLLS "${ROOTDIR}\admin\win\dlls" - -File "${ROOTDIR}\build\tomahawk.exe" -File "${ROOTDIR}\LICENSE.txt" - -; QT stuff: -File "${DLLS}\QtCore4.dll" -File "${DLLS}\QtGui4.dll" -File "${DLLS}\QtNetwork4.dll" -File "${DLLS}\QtSql4.dll" -File "${DLLS}\QtXml4.dll" -SetOutPath "$INSTDIR\sqldrivers" -File "${DLLS}\sqldrivers\qsqlite4.dll" -SetOutPath "$INSTDIR" - -; Cygwin/c++ stuff -File "${DLLS}\cygmad-0.dll" -File "${DLLS}\libgcc_s_dw2-1.dll" -File "${DLLS}\mingwm10.dll" - -; Audio stuff -File "${DLLS}\libmad.dll" -File "${DLLS}\librtaudio.dll" - -; Other -File "${DLLS}\libqjson.dll" -File "${DLLS}\libqxtweb-standalone.dll" -File "${DLLS}\libtag.dll" - -;create desktop shortcut -CreateShortCut "$DESKTOP\${MUI_PRODUCT}.lnk" "$INSTDIR\${MUI_FILE}.exe" "" - -;create start-menu items -CreateDirectory "$SMPROGRAMS\${MUI_PRODUCT}" -CreateShortCut "$SMPROGRAMS\${MUI_PRODUCT}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 -CreateShortCut "$SMPROGRAMS\${MUI_PRODUCT}\${MUI_PRODUCT}.lnk" "$INSTDIR\${MUI_FILE}.exe" "" "$INSTDIR\${MUI_FILE}.exe" 0 - -;write uninstall information to the registry -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${MUI_PRODUCT}" "DisplayName" "${MUI_PRODUCT} (remove only)" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${MUI_PRODUCT}" "UninstallString" "$INSTDIR\Uninstall.exe" - -WriteUninstaller "$INSTDIR\Uninstall.exe" - -SectionEnd - - -;-------------------------------- -;Uninstaller Section -Section "Uninstall" - -;Delete Files -RMDir /r "$INSTDIR\*.*" - -;Remove the installation directory -RMDir "$INSTDIR" - -;Delete Start Menu Shortcuts -Delete "$DESKTOP\${MUI_PRODUCT}.lnk" -Delete "$SMPROGRAMS\${MUI_PRODUCT}\*.*" -RmDir "$SMPROGRAMS\${MUI_PRODUCT}" - -;Delete Uninstaller And Unistall Registry Entries -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${MUI_PRODUCT}" -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${MUI_PRODUCT}" - -SectionEnd - - -Function un.onUninstSuccess - MessageBox MB_OK "You have successfully uninstalled ${MUI_PRODUCT}." -FunctionEnd +;Tomahawk installer script. + +;----------------------------------------------------------------------------- +; Some installer script options (comment-out options not required) +;----------------------------------------------------------------------------- +;!define OPTION_LICENSE_AGREEMENT +!define OPTION_SECTION_SC_START_MENU +!define OPTION_SECTION_SC_DESKTOP +!define OPTION_SECTION_SC_QUICK_LAUNCH +!define OPTION_FINISHPAGE +!define OPTION_FINISHPAGE_LAUNCHER +!define OPTION_FINISHPAGE_RELEASE_NOTES + +;----------------------------------------------------------------------------- +; Some paths. +;----------------------------------------------------------------------------- +!define MING_PATH "/usr/i686-pc-mingw32/sys-root/mingw" +!define MING_BIN "${MING_PATH}/bin" +!define MING_DLL_PATH "${MING_BIN}" +!define ROOT_PATH "..\.." ; assuming the script is in ROOT/admin/win/ +!define QT_DLL_PATH "${MING_BIN}" +!define SQLITE_DLL_PATH "${MING_PATH}/lib/qt4/plugins/sqldrivers/" +!define RTAUDIO_DLL_PATH "../../rtaudio/" +!define QXTWEB_DLL_PATH "../../qxtweb-standalone/" + +;----------------------------------------------------------------------------- +; Increment installer revision number as part of this script. +;----------------------------------------------------------------------------- +!define /file REVISION_LAST revision.txt +!define /math REVISION ${REVISION_LAST} + 1 +!delfile revision.txt +!appendfile revision.txt ${REVISION} + +!define VER_MAJOR "0" +!define VER_MINOR "1" +!define VER_BUILD "1" + +!define VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}" + +;----------------------------------------------------------------------------- +; Installer build timestamp. +;----------------------------------------------------------------------------- +!define /date BUILD_TIME "built on %Y/%m/%d at %I:%M %p (rev. ${REVISION})" + +;----------------------------------------------------------------------------- +; Initial installer setup and definitions. +;----------------------------------------------------------------------------- +Name "Tomahawk" +Caption "Tomahawk Installer" +BrandingText "Tomahawk ${VERSION} -- ${BUILD_TIME}" +OutFile "tomahawk-${VERSION}.exe" +InstallDir "$PROGRAMFILES\Tomahawk" +InstallDirRegKey HKCU "Software\Tomahawk" "" +InstType Standard +InstType Full +InstType Minimal +CRCCheck On +SetCompressor /SOLID lzma +RequestExecutionLevel user ;Using the UAC plugin. +ReserveFile tomahawk.ini +ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll" + +;----------------------------------------------------------------------------- +; Include some required header files. +;----------------------------------------------------------------------------- +!include LogicLib.nsh ;Used by APPDATA uninstaller. +!include nsDialogs.nsh ;Used by APPDATA uninstaller. +!include MUI2.nsh ;Used by APPDATA uninstaller. +!include InstallOptions.nsh ;Required by MUI2 to support old MUI_INSTALLOPTIONS. +!include Memento.nsh ;Remember user selections. +!include WinVer.nsh ;Windows version detection. +!include WordFunc.nsh ;Used by VersionCompare macro function. +!include UAC.nsh ;Used by the UAC elevation to install as user or admin. + +;----------------------------------------------------------------------------- +; Memento selections stored in registry. +;----------------------------------------------------------------------------- +!define MEMENTO_REGISTRY_ROOT HKLM +!define MEMENTO_REGISTRY_KEY Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk + +;----------------------------------------------------------------------------- +; Modern User Interface (MUI) defintions and setup. +;----------------------------------------------------------------------------- +!define MUI_ABORTWARNING +!define MUI_ICON installer.ico +!define MUI_UNICON installer.ico +!define MUI_WELCOMEFINISHPAGE_BITMAP welcome.bmp +!define MUI_WELCOMEPAGE_TITLE "Tomahawk ${VERSION} Setup$\r$\nInstaller Build Revision ${REVISION}" +!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation.$\r$\n$\r$\n$_CLICK" +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP page_header.bmp +!define MUI_COMPONENTSPAGE_SMALLDESC +!define MUI_FINISHPAGE_TITLE "Tomahawk Install Completed" +!define MUI_FINISHPAGE_LINK "Click here to visit the Tomahawk website." +!define MUI_FINISHPAGE_LINK_LOCATION "http://tomahawk-player.org/" +!define MUI_FINISHPAGE_NOREBOOTSUPPORT +!ifdef OPTION_FINISHPAGE_RELEASE_NOTES + !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED + !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\NOTES.txt" + !define MUI_FINISHPAGE_SHOWREADME_TEXT "Show release notes" +!endif +!ifdef OPTION_FINISHPAGE_LAUNCHER + !define MUI_FINISHPAGE_NOAUTOCLOSE + !define MUI_FINISHPAGE_RUN + !define MUI_FINISHPAGE_RUN_FUNCTION "LaunchTomahawk" +!endif + +;----------------------------------------------------------------------------- +; Page macros. +;----------------------------------------------------------------------------- +!insertmacro MUI_PAGE_WELCOME +!ifdef OPTION_LICENSE_AGREEMENT + !insertmacro MUI_PAGE_LICENSE "LICENSE.txt" +!endif +Page custom PageReinstall PageLeaveReinstall +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!ifdef OPTION_FINISHPAGE + !insertmacro MUI_PAGE_FINISH +!endif +!insertmacro MUI_UNPAGE_CONFIRM +UninstPage custom un.UnPageUserAppData un.UnPageUserAppDataLeave +!insertmacro MUI_UNPAGE_INSTFILES + +;----------------------------------------------------------------------------- +; Other MUI macros. +;----------------------------------------------------------------------------- +!insertmacro MUI_LANGUAGE "English" + +############################################################################## +# # +# FINISH PAGE LAUNCHER FUNCTIONS # +# # +############################################################################## + +Function LaunchTomahawk + ${UAC.CallFunctionAsUser} LaunchTomahawkAsUser +FunctionEnd + +Function LaunchTomahawkAsUser + Exec "$INSTDIR\tomahawk.exe" +FunctionEnd + +############################################################################## +# # +# RE-INSTALLER FUNCTIONS # +# # +############################################################################## + +Function PageReinstall + ReadRegStr $R0 HKLM "Software\Tomahawk" "" + StrCmp $R0 "" 0 +2 + Abort + + ;Detect version + ReadRegDWORD $R0 HKLM "Software\Tomahawk" "VersionMajor" + IntCmp $R0 ${VER_MAJOR} minor_check new_version older_version + minor_check: + ReadRegDWORD $R0 HKLM "Software\Tomahawk" "VersionMinor" + IntCmp $R0 ${VER_MINOR} build_check new_version older_version + build_check: + ReadRegDWORD $R0 HKLM "Software\Tomahawk" "VersionBuild" + IntCmp $R0 ${VER_BUILD} revision_check new_version older_version + revision_check: + ReadRegDWORD $R0 HKLM "Software\Tomahawk" "VersionRevision" + IntCmp $R0 ${REVISION} same_version new_version older_version + + new_version: + !insertmacro INSTALLOPTIONS_WRITE "tomahawk.ini" "Field 1" "Text" "An older version of Tomahawk is installed on your system. It is recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue." + !insertmacro INSTALLOPTIONS_WRITE "tomahawk.ini" "Field 2" "Text" "Uninstall before installing" + !insertmacro INSTALLOPTIONS_WRITE "tomahawk.ini" "Field 3" "Text" "Do not uninstall" + !insertmacro MUI_HEADER_TEXT "Already Installed" "Choose how you want to install Tomahawk." + StrCpy $R0 "1" + Goto reinst_start + + older_version: + !insertmacro INSTALLOPTIONS_WRITE "tomahawk.ini" "Field 1" "Text" "A newer version of Tomahawk is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue." + !insertmacro INSTALLOPTIONS_WRITE "tomahawk.ini" "Field 2" "Text" "Uninstall before installing" + !insertmacro INSTALLOPTIONS_WRITE "tomahawk.ini" "Field 3" "Text" "Do not uninstall" + !insertmacro MUI_HEADER_TEXT "Already Installed" "Choose how you want to install Tomahawk." + StrCpy $R0 "1" + Goto reinst_start + + same_version: + !insertmacro INSTALLOPTIONS_WRITE "tomahawk.ini" "Field 1" "Text" "Tomahawk ${VERSION} is already installed.\r\nSelect the operation you want to perform and click Next to continue." + !insertmacro INSTALLOPTIONS_WRITE "tomahawk.ini" "Field 2" "Text" "Add/Reinstall components" + !insertmacro INSTALLOPTIONS_WRITE "tomahawk.ini" "Field 3" "Text" "Uninstall Tomahawk" + !insertmacro MUI_HEADER_TEXT "Already Installed" "Choose the maintenance option to perform." + StrCpy $R0 "2" + + reinst_start: + !insertmacro INSTALLOPTIONS_DISPLAY "tomahawk.ini" +FunctionEnd + +Function PageLeaveReinstall + !insertmacro INSTALLOPTIONS_READ $R1 "tomahawk.ini" "Field 2" "State" + StrCmp $R0 "1" 0 +2 + StrCmp $R1 "1" reinst_uninstall reinst_done + StrCmp $R0 "2" 0 +3 + StrCmp $R1 "1" reinst_done reinst_uninstall + reinst_uninstall: + ReadRegStr $R1 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "UninstallString" + HideWindow + ClearErrors + ExecWait '$R1 _?=$INSTDIR' + IfErrors no_remove_uninstaller + IfFileExists "$INSTDIR\tomahawk.exe" no_remove_uninstaller + Delete $R1 + RMDir $INSTDIR + no_remove_uninstaller: + StrCmp $R0 "2" 0 +3 + UAC::Unload + Quit + BringToFront + reinst_done: +FunctionEnd + +############################################################################## +# # +# INSTALLER SECTIONS # +# # +############################################################################## + +Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER + SectionIn 1 2 3 RO + SetDetailsPrint listonly + + SetDetailsPrint textonly + DetailPrint "Installing Tomahawk Player essentials." + SetDetailsPrint listonly + SetOutPath "$INSTDIR" + + ;Main executable. + File "${ROOT_PATH}\build\tomahawk.exe" + + ;License & release notes. + File "${ROOT_PATH}\LICENSE.txt" + File /oname=NOTES.txt RELEASE_NOTES.txt + + ;QT stuff: + File "${QT_DLL_PATH}\QtCore4.dll" + File "${QT_DLL_PATH}\QtGui4.dll" + File "${QT_DLL_PATH}\QtNetwork4.dll" + File "${QT_DLL_PATH}\QtSql4.dll" + File "${QT_DLL_PATH}\QtXml4.dll" + + ;SQLite driver + SetOutPath "$INSTDIR\sqldrivers" + File "${SQLITE_DLL_PATH}\qsqlite4.dll" + SetOutPath "$INSTDIR" + + ;Cygwin/c++ stuff + ;File "${MING_DLL_PATH}\cygmad-0.dll" + ;File "${MING_DLL_PATH}\libgcc_s_dw2-1.dll" + ;File "${MING_DLL_PATH}\mingwm10.dll" + File "${MING_DLL_PATH}\libgcc_s_sjlj-1.dll" + File "${MING_DLL_PATH}\libstdc++-6.dll" + + ;Audio stuff + ;File "${MING_DLL_PATH}\libmad.dll" + ;File "${MING_DLL_PATH}\librtaudio.dll" + + ;Other + File "${MING_DLL_PATH}\libqjson.dll" + File "${MING_DLL_PATH}\libtag.dll" + File "${MING_DLL_PATH}\libgloox-8.dll" + File "${MING_DLL_PATH}\libpng14-14.dll" + File "${MING_DLL_PATH}\zlib1.dll" + File "${MING_DLL_PATH}\libechonest.dll" + File "${RTAUDIO_DLL_PATH}\librtaudio.dll" + File "${QXTWEB_DLL_PATH}\libqxtweb-standalone.dll" +SectionEnd + +SectionGroup "Shortcuts" + +!ifdef OPTION_SECTION_SC_START_MENU + ${MementoSection} "Start Menu Program Group" SEC_START_MENU + SectionIn 1 2 + SetDetailsPrint textonly + DetailPrint "Adding shortcuts for the Tomahawk program group to the Start Menu." + SetDetailsPrint listonly + SetShellVarContext all + RMDir /r "$SMPROGRAMS\Tomahawk" + CreateDirectory "$SMPROGRAMS\Tomahawk" + CreateShortCut "$SMPROGRAMS\Tomahawk\LICENSE.lnk" "$INSTDIR\LICENSE.txt" + CreateShortCut "$SMPROGRAMS\Tomahawk\Tomahawk.lnk" "$INSTDIR\tomahawk.exe" + CreateShortCut "$SMPROGRAMS\Tomahawk\Release notes.lnk" "$INSTDIR\NOTES.txt" + CreateShortCut "$SMPROGRAMS\Tomahawk\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + SetShellVarContext current + ${MementoSectionEnd} +!endif + +!ifdef OPTION_SECTION_SC_DESKTOP + ${MementoSection} "Desktop Shortcut" SEC_DESKTOP + SectionIn 1 2 + SetDetailsPrint textonly + DetailPrint "Creating Desktop Shortcuts" + SetDetailsPrint listonly + CreateShortCut "$DESKTOP\Tomahawk.lnk" "$INSTDIR\tomahawk.exe" + ${MementoSectionEnd} +!endif + +!ifdef OPTION_SECTION_SC_QUICK_LAUNCH + ${MementoSection} "Quick Launch Shortcut" SEC_QUICK_LAUNCH + SectionIn 1 2 + SetDetailsPrint textonly + DetailPrint "Creating Quick Launch Shortcut" + SetDetailsPrint listonly + CreateShortCut "$QUICKLAUNCH\Tomahawk.lnk" "$INSTDIR\tomahawk.exe" + ${MementoSectionEnd} +!endif + +SectionGroupEnd + +${MementoSectionDone} + +; Installer section descriptions +;-------------------------------- +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN +!insertmacro MUI_DESCRIPTION_TEXT ${SEC_TOMAHAWK_PLAYER} "Tomahawk player essentials." +!insertmacro MUI_DESCRIPTION_TEXT ${SEC_START_MENU} "Tomahawk program group." +!insertmacro MUI_DESCRIPTION_TEXT ${SEC_DESKTOP} "Desktop shortcut for Tomahawk." +!insertmacro MUI_DESCRIPTION_TEXT ${SEC_QUICK_LAUNCH} "Quick Launch shortcut for Tomahawk." +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +Section -post + + ;Uninstaller file. + SetDetailsPrint textonly + DetailPrint "Writing Uninstaller" + SetDetailsPrint listonly + WriteUninstaller $INSTDIR\Uninstall.exe + + ;Registry keys required for installer version handling and uninstaller. + SetDetailsPrint textonly + DetailPrint "Writing Installer Registry Keys" + SetDetailsPrint listonly + + ;Version numbers used to detect existing installation version for comparisson. + WriteRegStr HKLM "Software\Tomahawk" "" $INSTDIR + WriteRegDWORD HKLM "Software\Tomahawk" "VersionMajor" "${VER_MAJOR}" + WriteRegDWORD HKLM "Software\Tomahawk" "VersionMinor" "${VER_MINOR}" + WriteRegDWORD HKLM "Software\Tomahawk" "VersionRevision" "${REVISION}" + WriteRegDWORD HKLM "Software\Tomahawk" "VersionBuild" "${VER_BUILD}" + + ;Add or Remove Programs entry. + WriteRegExpandStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "UninstallString" '"$INSTDIR\Uninstall.exe"' + WriteRegExpandStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "InstallLocation" "$INSTDIR" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "DisplayName" "Tomahawk" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "Publisher" "Tomahawk-player.org" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "DisplayIcon" "$INSTDIR\Uninstall.exe,0" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "DisplayVersion" "${VERSION}" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "VersionMajor" "${VER_MAJOR}" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "VersionMinor" "${VER_MINOR}.${REVISION}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "URLInfoAbout" "http://tomahawk-player.org/" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "HelpLink" "http://tomahawk-player.org/" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "NoModify" "1" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "NoRepair" "1" + + SetDetailsPrint textonly + DetailPrint "Finsihed." +SectionEnd + +############################################################################## +# # +# UNINSTALLER SECTION # +# # +############################################################################## + +Var UnPageUserAppDataDialog +Var UnPageUserAppDataCheckbox +Var UnPageUserAppDataCheckbox_State +Var UnPageUserAppDataEditBox + +Function un.UnPageUserAppData + !insertmacro MUI_HEADER_TEXT "Uninstall Tomahawk" "Remove Tomahawk's data folder from your computer." + nsDialogs::Create /NOUNLOAD 1018 + Pop $UnPageUserAppDataDialog + + ${If} $UnPageUserAppDataDialog == error + Abort + ${EndIf} + + ${NSD_CreateLabel} 0 0 100% 12u "Do you want to delete Tomahawk's data folder?" + Pop $0 + + ${NSD_CreateText} 0 13u 100% 12u "$APPDATA\Tomahawk" + Pop $UnPageUserAppDataEditBox + SendMessage $UnPageUserAppDataEditBox ${EM_SETREADONLY} 1 0 + + ${NSD_CreateLabel} 0 46u 100% 24u "Leave unchecked to keep the data folder for later use or check to delete the data folder." + Pop $0 + + ${NSD_CreateCheckbox} 0 71u 100% 8u "Yes, delete this data folder." + Pop $UnPageUserAppDataCheckbox + + nsDialogs::Show +FunctionEnd + +Function un.UnPageUserAppDataLeave + ${NSD_GetState} $UnPageUserAppDataCheckbox $UnPageUserAppDataCheckbox_State +FunctionEnd + +Section Uninstall + IfFileExists "$INSTDIR\tomahawk.exe" tomahawk_installed + MessageBox MB_YESNO "It does not appear that Tomahawk is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?" IDYES tomahawk_installed + Abort "Uninstall aborted by user" + tomahawk_installed: + + ;Delete registry keys. + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" + DeleteRegValue HKLM "Software\Tomahawk" "VersionBuild" + DeleteRegValue HKLM "Software\Tomahawk" "VersionMajor" + DeleteRegValue HKLM "Software\Tomahawk" "VersionMinor" + DeleteRegValue HKLM "Software\Tomahawk" "VersionRevision" + DeleteRegValue HKLM "Software\Tomahawk" "" + DeleteRegKey HKLM "Software\Tomahawk" + + ;Start menu shortcuts. + !ifdef OPTION_SECTION_SC_START_MENU + SetShellVarContext all + RMDir /r "$SMPROGRAMS\Tomahawk" + SetShellVarContext current + !endif + + ;Desktop shortcut. + !ifdef OPTION_SECTION_SC_DESKTOP + IfFileExists "$DESKTOP\Tomahawk.lnk" 0 +2 + Delete "$DESKTOP\Tomahawk.lnk" + !endif + + ;Quick Launch shortcut. + !ifdef OPTION_SECTION_SC_QUICK_LAUNCH + IfFileExists "$QUICKLAUNCH\Tomahawk.lnk" 0 +2 + Delete "$QUICKLAUNCH\Tomahawk.lnk" + !endif + + ;Remove all the Program Files. + RMDir /r $INSTDIR + + ;Uninstall User Data if option is checked, otherwise skip. + ${If} $UnPageUserAppDataCheckbox_State == ${BST_CHECKED} + RMDir /r "$APPDATA\Tomahawk" + ${EndIf} + + SetDetailsPrint textonly + DetailPrint "Finsihed." +SectionEnd + +############################################################################## +# # +# NSIS Installer Event Handler Functions # +# # +############################################################################## + +Function .onInit + !insertmacro INSTALLOPTIONS_EXTRACT "tomahawk.ini" + + ;Remove Quick Launch option from Windows 7, as no longer applicable - usually. + ${IfNot} ${AtMostWinVista} + SectionSetText ${SEC_QUICK_LAUNCH} "Quick Launch Shortcut (N/A)" + SectionSetFlags ${SEC_QUICK_LAUNCH} ${SF_RO} + SectionSetInstTypes ${SEC_QUICK_LAUNCH} 0 + ${EndIf} + + ${MementoSectionRestore} + + UAC_Elevate: + UAC::RunElevated + StrCmp 1223 $0 UAC_ElevationAborted ; UAC dialog aborted by user? + StrCmp 0 $0 0 UAC_Err ; Error? + StrCmp 1 $1 0 UAC_Success ;Are we the real deal or just the wrapper? + Quit + + UAC_Err: + MessageBox MB_ICONSTOP "Unable to elevate, error $0" + Abort + + UAC_ElevationAborted: + Abort + + UAC_Success: + StrCmp 1 $3 +4 ;Admin? + StrCmp 3 $1 0 UAC_ElevationAborted ;Try again? + MessageBox MB_ICONSTOP "This installer requires admin access, try again" + goto UAC_Elevate + + ;Prevent multiple instances. + System::Call 'kernel32::CreateMutexA(i 0, i 0, t "tomahawkInstaller") i .r1 ?e' + Pop $R0 + StrCmp $R0 0 +3 + MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running." + Abort +FunctionEnd + +Function .onInstSuccess + ${MementoSectionSave} + UAC::Unload ;Must call unload! +FunctionEnd + +Function .onInstFailed + UAC::Unload ;Must call unload! +FunctionEnd + +############################################################################## +# # +# NSIS Uninstaller Event Handler Functions # +# # +############################################################################## + +Function un.onInit + + UAC_Elevate: + UAC::RunElevated + StrCmp 1223 $0 UAC_ElevationAborted ; UAC dialog aborted by user? + StrCmp 0 $0 0 UAC_Err ; Error? + StrCmp 1 $1 0 UAC_Success ;Are we the real deal or just the wrapper? + Quit + + UAC_Err: + MessageBox MB_ICONSTOP "Unable to elevate, error $0" + Abort + + UAC_ElevationAborted: + Abort + + UAC_Success: + StrCmp 1 $3 +4 ;Admin? + StrCmp 3 $1 0 UAC_ElevationAborted ;Try again? + MessageBox MB_ICONSTOP "This uninstaller requires admin access, try again" + goto UAC_Elevate + + ;Prevent multiple instances. + System::Call 'kernel32::CreateMutexA(i 0, i 0, t "tomahawkUninstaller") i .r1 ?e' + Pop $R0 + StrCmp $R0 0 +3 + MessageBox MB_OK|MB_ICONEXCLAMATION "This uninstaller is already running." + Abort +FunctionEnd + +Function un.onUnInstSuccess + UAC::Unload ;Must call unload! +FunctionEnd + +Function un.onUnInstFailed + UAC::Unload ;Must call unload! +FunctionEnd diff --git a/admin/win/welcome.bmp b/admin/win/welcome.bmp new file mode 100755 index 0000000000000000000000000000000000000000..8fc4078bf76dadc2352b1ac84a354af657c692c1 GIT binary patch literal 154542 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

%0oLd6n+-L^Qu_;|s~#8-UwifzEAf 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 Z_!u=lz?xBa`E}(0Yrn?FsPSO^{{a58ip&52 literal 0 HcmV?d00001 From 20d94a141994bc385f7f7d5762a64ac4a55bdd6a Mon Sep 17 00:00:00 2001 From: Steven Robertson Date: Thu, 4 Nov 2010 23:29:20 +0000 Subject: [PATCH 2/2] Small change to handle the LOCALAPPDATA location for application data. --- admin/win/tomahawk.nsi | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/admin/win/tomahawk.nsi b/admin/win/tomahawk.nsi index d74b1b51c..691d7e7b8 100755 --- a/admin/win/tomahawk.nsi +++ b/admin/win/tomahawk.nsi @@ -16,12 +16,12 @@ ;----------------------------------------------------------------------------- !define MING_PATH "/usr/i686-pc-mingw32/sys-root/mingw" !define MING_BIN "${MING_PATH}/bin" -!define MING_DLL_PATH "${MING_BIN}" +!define MING_DLL_PATH "dlls" ; "${MING_BIN}" !define ROOT_PATH "..\.." ; assuming the script is in ROOT/admin/win/ -!define QT_DLL_PATH "${MING_BIN}" -!define SQLITE_DLL_PATH "${MING_PATH}/lib/qt4/plugins/sqldrivers/" -!define RTAUDIO_DLL_PATH "../../rtaudio/" -!define QXTWEB_DLL_PATH "../../qxtweb-standalone/" +!define QT_DLL_PATH "dlls" +!define SQLITE_DLL_PATH "dlls\sqldrivers" ; "${MING_PATH}/lib/qt4/plugins/sqldrivers/" +!define RTAUDIO_DLL_PATH "dlls" ; "../../rtaudio/" +!define QXTWEB_DLL_PATH "dlls" ; "../../qxtweb-standalone/" ;----------------------------------------------------------------------------- ; Increment installer revision number as part of this script. @@ -32,8 +32,8 @@ !appendfile revision.txt ${REVISION} !define VER_MAJOR "0" -!define VER_MINOR "1" -!define VER_BUILD "1" +!define VER_MINOR "0" +!define VER_BUILD "0" !define VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}" @@ -385,7 +385,7 @@ Function un.UnPageUserAppData ${NSD_CreateLabel} 0 0 100% 12u "Do you want to delete Tomahawk's data folder?" Pop $0 - ${NSD_CreateText} 0 13u 100% 12u "$APPDATA\Tomahawk" + ${NSD_CreateText} 0 13u 100% 12u "$LOCALAPPDATA\Tomahawk" Pop $UnPageUserAppDataEditBox SendMessage $UnPageUserAppDataEditBox ${EM_SETREADONLY} 1 0 @@ -441,7 +441,7 @@ Section Uninstall ;Uninstall User Data if option is checked, otherwise skip. ${If} $UnPageUserAppDataCheckbox_State == ${BST_CHECKED} - RMDir /r "$APPDATA\Tomahawk" + RMDir /r "$LOCALAPPDATA\Tomahawk" ${EndIf} SetDetailsPrint textonly