/admin/win/nsi/nsis_uac/uac.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 1518 lines · 1438 code · 39 blank · 41 comment · 66 complexity · c61bd6a7e2029a603bf357d381fbdb94 MD5 · raw file

  1. //Copyright (C) 2007 Anders Kjersem. Licensed under the zlib/libpng license, see License.txt for details.
  2. /*
  3. UAC plugin for NSIS
  4. ===================
  5. Compiled with VC6+PlatformSDK (StdCall & MinimizeSize)
  6. Todo:
  7. -----
  8. ¤GetCurrentDir in elevated parent and pass along to outer process for Exec* (or somekind of ipc to request it if workingdir param is empty)
  9. X¤Check if secondary logon service is running in SysElevationPresent() on NT5
  10. ¤Use IsUserAnAdmin? MAKEINTRESOURCE(680) export on 2k (it even exists on NT4?) //http://forums.winamp.com/showthread.php?s=&threadid=195020
  11. ¤AllowSetForegroundWindow
  12. ¤Use RPC instead of WM_COPYDATA for IPC
  13. ¤Autodetect "best" default admin user in MyRunAs
  14. ¤Use ChangeWindowMessageFilter so we can get >WM_USER msg success feedback and possibly fill the log with detailprints
  15. ¤Hide IPC window inside inner instance window? (Could this add unload problems?)
  16. ¤CREATE_PRESERVE_CODE_AUTHZ_LEVEL? http://msdn2.microsoft.com/en-us/library/ms684863.aspx
  17. ¤UpdateProcThreadAttribute?
  18. ¤Consent UI on XP ?
  19. ¤All langs in single file; [MyRunAsStrings]>LangSections != 0 then load strings from [langid] sections
  20. ¤BroadcastSystemMessage to help with SetForeground
  21. ¤UAC::StackPop
  22. Notes:
  23. ------
  24. Primary integrity levels:
  25. Name SID RID
  26. Low Mandatory Level S-1-16-4096 0x1000
  27. Medium Mandatory Level S-1-16-8192 0x2000
  28. High Mandatory Level S-1-16-12288 0x3000
  29. System Mandatory Level S-1-16-16384 0x4000
  30. */
  31. #define UAC_HACK_Clammerz //ugly messagebox focus hack for .onInit
  32. #define UAC_HACK_FGWND1 //super ugly fullscreen invisible window for focus tricks
  33. #define UAC_INITIMPORTS
  34. #include "UAC.h"
  35. #include <objbase.h>//CoInitialize
  36. #include "NSISUtil.h"
  37. using namespace NSIS;
  38. NSISUTIL_INIT();
  39. #define ERRAPP_BADIPCSRV (0x20000000|1)
  40. #define SW_INVALID ((WORD)-1)
  41. #define IPCTOUT_DEF (1000*3) //default timeout for IPC messages
  42. #define IPCTOUT_SHORT 1500
  43. #define IPCTOUT_LONG (IPCTOUT_DEF*2)
  44. enum _IPCSRVWNDMSG
  45. {
  46. IPC_GETEXITCODE=WM_USER, //Get exit-code of the process spawned by the last call to ExecWait/ShellExecWait
  47. IPC_ELEVATEAGAIN,
  48. IPC_GETSRVPID, //Get PID of outer process
  49. IPC_GETSRVHWND, //Get $HWNDParent of outer process
  50. IPC_EXECCODESEGMENT, //wp:pos | lp:hwnd | returns ErrorCode+1
  51. IPC_GETOUTERPROCESSTOKEN,
  52. #ifdef UAC_HACK_FGWND1
  53. IPC_HACKFINDRUNAS,
  54. #endif
  55. };
  56. enum _COPYDATAID
  57. {
  58. CDI_SHEXEC=666, //returns WindowsErrorCode+1
  59. CDI_SYNCVAR,
  60. CDI_STACKPUSH,
  61. };
  62. typedef struct
  63. {
  64. UINT VarId;
  65. NSISCH buf[ANYSIZE_ARRAY];
  66. } IPC_SYNCVAR;
  67. typedef struct
  68. {
  69. HWND hwnd;
  70. bool Wait;
  71. bool UseCreateProcess;
  72. WORD ShowMode;
  73. NSISCH*strExec;
  74. NSISCH*strParams;
  75. NSISCH*strWorkDir;
  76. NSISCH*strVerb;
  77. NSISCH buf[ANYSIZE_ARRAY];
  78. } IPC_SHEXEC;
  79. typedef struct
  80. {
  81. HINSTANCE hInstance;
  82. HWND hSrvIPC;
  83. BYTE DllRef;
  84. bool UseIPC;
  85. bool CheckedIPCParam;
  86. UINT NSISStrLen;
  87. //IPC Server stuff:
  88. HANDLE hElevatedProcess;
  89. HANDLE threadIPC;
  90. DWORD LastWaitExitCode;//Exit code of process started from last call to ExecWait/ShellExecWait
  91. NSIS::extra_parameters*pXParams;
  92. bool ElevateAgain;
  93. //DelayLoadedModules:
  94. HMODULE hModAdvAPI;
  95. } GLOBALS;
  96. GLOBALS g = {0};
  97. void StopIPCSrv();
  98. DWORD _GetElevationType(TOKEN_ELEVATION_TYPE* pTokenElevType);
  99. bool GetIPCSrvWndFromParams(HWND&hwndOut);
  100. #if _MSC_VER >= 1400 //MSVC 2005 wants to pull in the CRT, let's try to help it out
  101. void* __cdecl memset(void*mem,int c,size_t len)
  102. {
  103. char *p=(char*)mem;
  104. while (len-- > 0){*p++=c;}
  105. return mem;
  106. }
  107. #endif
  108. FORCEINLINE NSISCH* GetIPCWndClass() { return _T("NSISUACIPC"); }
  109. FORCEINLINE bool StrCmpI(LPCTSTR s1,LPCTSTR s2) {return 0==lstrcmpi(s1,s2);}
  110. LPTSTR StrNextChar(LPCTSTR Str) { return CharNext(Str); }
  111. bool StrContainsWhiteSpace(LPCTSTR s) { if (s) {while(*s && *s>_T(' '))s=StrNextChar(s);if (*s)return true;}return false; }
  112. DWORD GetSysVer(bool Major=true)
  113. {
  114. OSVERSIONINFO ovi = { sizeof(ovi) };
  115. if ( !GetVersionEx(&ovi) ) return 0;
  116. return Major ? ovi.dwMajorVersion : ovi.dwMinorVersion;
  117. }
  118. #define GetOSVerMaj() (GetSysVer(true))
  119. #define GetOSVerMin() (GetSysVer(false))
  120. UINT_PTR StrToUInt(LPTSTR s,bool ForceHEX=false,BOOL*pFoundBadChar=0)
  121. {
  122. UINT_PTR v=0;
  123. BYTE base=ForceHEX?16:10;
  124. if (pFoundBadChar)*pFoundBadChar=false;
  125. if ( !ForceHEX && *s=='0' && ((*(s=StrNextChar(s)))&~0x20)=='X' && (s=StrNextChar(s)) )base=16;
  126. for (TCHAR c=*s; c; c=*(s=StrNextChar(s)) )
  127. {
  128. if (c >= _T('0') && c <= _T('9')) c-='0';
  129. else if (base==16 && (c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') c=(c & 7) +9;
  130. else
  131. {
  132. if (pFoundBadChar /*&& c!=' '*/)*pFoundBadChar=true;
  133. break;
  134. }
  135. v*=base;v+=c;
  136. }
  137. return v;
  138. }
  139. LPTSTR FindExePathEnd(LPTSTR p)
  140. {
  141. if ( *p=='"' && *(++p) )
  142. {
  143. while( *p && *p!='"' )p=StrNextChar(p);
  144. if (*p)
  145. p=StrNextChar(p);
  146. else
  147. return 0;
  148. }
  149. else
  150. if ( *p!='/' )while( *p && *p!=' ' )p=StrNextChar(p);
  151. return p;
  152. }
  153. #ifdef FEAT_MSRUNASDLGMODHACK
  154. HHOOK g_MSRunAsHook;
  155. void MSRunAsDlgMod_Unload(void*hook)
  156. {
  157. if (hook)
  158. {
  159. //ASSERT(g_MSRunAsHook==hook);
  160. UnhookWindowsHookEx((HHOOK)hook);
  161. //g_MSRunAsHook=0;
  162. }
  163. }
  164. LRESULT CALLBACK MSRunAsDlgMod_ShellProc(int nCode,WPARAM wp,LPARAM lp)
  165. {
  166. CWPRETSTRUCT*pCWPS;
  167. if (nCode >= 0 && (pCWPS=(CWPRETSTRUCT*)lp) && WM_INITDIALOG==pCWPS->message)
  168. {
  169. TCHAR buf[30];
  170. GetClassName(pCWPS->hwnd,buf,COUNTOF(buf));
  171. if (!lstrcmpi(buf,_T("#32770")))
  172. {
  173. const UINT IDC_USRSAFER=0x106,IDC_OTHERUSER=0x104,IDC_SYSCRED=0x105;
  174. GetClassName(GetDlgItem(pCWPS->hwnd,IDC_SYSCRED),buf,COUNTOF(buf));
  175. if (!lstrcmpi(buf,_T("SysCredential"))) //make sure this is the run as dialog
  176. {
  177. MySndDlgItemMsg(pCWPS->hwnd,IDC_USRSAFER,BM_SETCHECK,BST_UNCHECKED);
  178. MySndDlgItemMsg(pCWPS->hwnd,IDC_OTHERUSER,BM_CLICK);
  179. }
  180. }
  181. }
  182. return CallNextHookEx(g_MSRunAsHook,nCode,wp,lp);
  183. }
  184. void* MSRunAsDlgMod_Init()
  185. {
  186. if(GetOSVerMaj()!=5 || GetOSVerMin()<1)return NULL;//only XP/2003
  187. return g_MSRunAsHook=SetWindowsHookEx(WH_CALLWNDPROCRET,MSRunAsDlgMod_ShellProc,0,GetCurrentThreadId());
  188. }
  189. #endif
  190. DWORD DllSelfAddRef()
  191. {
  192. NSISCH buf[MAX_PATH*5];//Lets hope $pluginsdir is shorter than this, only special builds could break this
  193. DWORD len=GetModuleFileName(g.hInstance,buf,MAX_PATH*5);
  194. if ( len && len<MAX_PATH*5 && LoadLibrary(buf) )
  195. {
  196. if (!g.DllRef)g.DllRef++;
  197. return NO_ERROR;
  198. }
  199. ASSERT(!"DllSelfAddRef failed!");
  200. return ERROR_BUFFER_OVERFLOW;
  201. }
  202. FORCEINLINE DWORD MaintainDllSelfRef() //Call this from every exported function to prevent NSIS from unloading our plugin
  203. {
  204. if(!g.CheckedIPCParam && !g.DllRef)
  205. {
  206. HWND hSrv;
  207. g.CheckedIPCParam=true;
  208. g.UseIPC=GetIPCSrvWndFromParams(hSrv);
  209. if(g.UseIPC)
  210. {
  211. g.DllRef++;
  212. g.hSrvIPC=hSrv;
  213. }
  214. }
  215. return (g.DllRef)?DllSelfAddRef():NO_ERROR;
  216. }
  217. DWORD SendIPCMsg(UINT Msg,WPARAM wp,LPARAM lp,DWORD_PTR&MsgRet,DWORD tout=IPCTOUT_DEF,const HWND hIPCSrv=g.hSrvIPC)
  218. {
  219. if (tout==INFINITE) //BUGFIX: SendMessageTimeout(...,INFINITE,...) seems to be broken, SendMessageTimeout(...,SMTO_NORMAL,0,..) seems to work but why take the chance
  220. {
  221. MsgRet=SendMessage(hIPCSrv,Msg,wp,lp);
  222. return NO_ERROR;
  223. }
  224. if ( SendMessageTimeout(hIPCSrv,Msg,wp,lp,SMTO_NORMAL,tout,&MsgRet) )return NO_ERROR;
  225. return (tout=GetLastError()) ? tout : ERROR_TIMEOUT;
  226. }
  227. void _Unload()
  228. {
  229. StopIPCSrv();
  230. if (g.DllRef)
  231. {
  232. g.DllRef=0;
  233. FreeLibrary(g.hInstance);
  234. //Why bother?> FreeLibrary(g.hModAdvAPI);
  235. }
  236. }
  237. DWORD DelayLoadGetProcAddr(void**ppProc,HMODULE hLib,LPCSTR Export)
  238. {
  239. ASSERT(ppProc && hLib && Export);
  240. if (!*ppProc)
  241. {
  242. *ppProc=GetProcAddress(hLib,Export);
  243. if (!*ppProc)return GetLastError();
  244. }
  245. return NO_ERROR;
  246. }
  247. DWORD DelayLoadDlls()
  248. {
  249. #ifdef UNICODE
  250. # define __DLD_FUNCSUFFIX "W"
  251. # else
  252. # define __DLD_FUNCSUFFIX "A"
  253. # endif
  254. if (!g.hModAdvAPI) //using g.hModAdvAPI to test if this is the first time we have been called
  255. {
  256. struct
  257. {
  258. HMODULE*pMod;
  259. LPCSTR DllName;//NOTE: Always using ANSI strings to save a couple of bytes
  260. }
  261. dld[]=
  262. {
  263. {&g.hModAdvAPI,"AdvAPI32"},
  264. {0}
  265. };
  266. DWORD ec;
  267. UINT o;
  268. for (o=0; dld[o].pMod; ++o)
  269. if ( !(*dld[o].pMod=LoadLibraryA(dld[o].DllName)) )
  270. return GetLastError();
  271. struct
  272. {
  273. HMODULE hMod;
  274. void**ppProc;
  275. LPCSTR Export;
  276. bool Optional;
  277. }
  278. dldprocs[]=
  279. {
  280. {GetModuleHandle(_T("USER32")),(void**)&_AllowSetForegroundWindow,"AllowSetForegroundWindow",true},
  281. {g.hModAdvAPI,(void**)&_OpenProcessToken, "OpenProcessToken"},
  282. {g.hModAdvAPI,(void**)&_OpenThreadToken, "OpenThreadToken"},
  283. {g.hModAdvAPI,(void**)&_GetTokenInformation, "GetTokenInformation"},
  284. {g.hModAdvAPI,(void**)&_AllocateAndInitializeSid, "AllocateAndInitializeSid"},
  285. {g.hModAdvAPI,(void**)&_FreeSid, "FreeSid"},
  286. {g.hModAdvAPI,(void**)&_EqualSid, "EqualSid"},
  287. {g.hModAdvAPI,(void**)&_CheckTokenMembership, "CheckTokenMembership",true},
  288. #ifdef FEAT_CUSTOMRUNASDLG
  289. {g.hModAdvAPI,(void**)&_GetUserName, "GetUserName" __DLD_FUNCSUFFIX},
  290. {g.hModAdvAPI,(void**)&_CreateProcessWithLogonW,"CreateProcessWithLogonW",true},
  291. {LoadLibraryA("SECUR32"),(void**)&_GetUserNameEx,"GetUserNameEx" __DLD_FUNCSUFFIX,true},//We never free this library
  292. #endif
  293. {0}
  294. };
  295. //#undef __DLD_FUNCSUFFIX
  296. for (o=0; dldprocs[o].hMod; ++o)
  297. if (ec=DelayLoadGetProcAddr(dldprocs[o].ppProc,dldprocs[o].hMod,dldprocs[o].Export) && !dldprocs[o].Optional)
  298. {
  299. TRACEF("DelayLoadDlls failed to find %s in %X\n",dldprocs[o].Export,dldprocs[o].hMod);
  300. return ec;
  301. }
  302. }
  303. return NO_ERROR;
  304. }
  305. void AllowOuterInstanceWindowFocus()
  306. {
  307. if (g.UseIPC)
  308. {
  309. DWORD_PTR MsgRet;
  310. if (!SendIPCMsg(IPC_GETSRVPID,0,0,MsgRet,IPCTOUT_SHORT) && MsgRet && _AllowSetForegroundWindow)_AllowSetForegroundWindow(MsgRet);
  311. }
  312. }
  313. DWORD SyncVars(HWND hwndNSIS)
  314. {
  315. DWORD i,ec=NO_ERROR;
  316. IPC_SYNCVAR*pSV=0;
  317. if (!g.UseIPC)return NO_ERROR;
  318. g.NSISStrLen=NSIS::StrSize;
  319. TRACEF("SyncVars: g.NSISStrLen=%d\n",g.NSISStrLen);ASSERT(g.NSISStrLen>10);
  320. DWORD cbStruct=FIELD_OFFSET(IPC_SYNCVAR,buf[g.NSISStrLen+1]);
  321. pSV=(IPC_SYNCVAR*)MemAlloc(cbStruct);
  322. if (!pSV)
  323. goto die_GLE;
  324. else
  325. {
  326. COPYDATASTRUCT cds={CDI_SYNCVAR,cbStruct,pSV};
  327. for (i=0;i<__INST_LAST && !ec;++i)
  328. {
  329. pSV->VarId=i;
  330. lstrcpyn(pSV->buf,GetVar(i),g.NSISStrLen);
  331. DWORD MsgRet;//TRACEF("SyncVars: (%d)%s|\n",i,pSV->buf);
  332. if (!(ec=SendIPCMsg(WM_COPYDATA,(WPARAM)hwndNSIS,(LPARAM)&cds,MsgRet,3000 )))ec=MsgRet-1;
  333. }
  334. }
  335. return ec;
  336. die_GLE:
  337. return GetLastError();
  338. }
  339. DWORD _Exec(HWND hwnd,NSISCH*Verb,NSISCH*Exec,NSISCH*Params,NSISCH*WorkDir,WORD ShowWnd,bool Wait,bool UseCreateProcess)
  340. {
  341. DWORD ec;
  342. NSISCH*buf=0;
  343. SHELLEXECUTEINFO sei={sizeof(SHELLEXECUTEINFO)};
  344. sei.hwnd =hwnd;
  345. sei.nShow =(ShowWnd!=SW_INVALID)?ShowWnd:SW_NORMAL;
  346. sei.fMask =SEE_MASK_FLAG_DDEWAIT;
  347. sei.lpFile =(Exec&&*Exec) ?Exec:0;
  348. sei.lpParameters=(Params&&*Params) ?Params:0;
  349. sei.lpDirectory =(WorkDir&&*WorkDir) ?WorkDir:0;
  350. sei.lpVerb =(Verb&&*Verb) ?Verb:0;
  351. 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);
  352. if (UseCreateProcess)
  353. {
  354. STARTUPINFO si={sizeof(STARTUPINFO)};
  355. if (ShowWnd != SW_INVALID)
  356. {
  357. si.dwFlags|=STARTF_USESHOWWINDOW;
  358. si.wShowWindow=sei.nShow;
  359. }
  360. PROCESS_INFORMATION pi;
  361. const NSISCH*Q=( (*Exec!='"') && (*Params) && StrContainsWhiteSpace(Exec)) ? _T("\"") : _T("");//Add extra quotes to program part of command-line?
  362. const DWORD len= ((*Q)?2:0) + lstrlen(Exec) + 1 + lstrlen(Params) + 1;
  363. buf=(NSISCH*)NSIS::MemAlloc(len*sizeof(NSISCH));
  364. if (!buf)return ERROR_OUTOFMEMORY;
  365. //Build string for CreateProcess, "[Q]<Exec>[Q][Space]<Params>"
  366. wsprintf(buf,_T("%s%s%s%s%s"),Q,Exec,Q,((*Params)?_T(" "):_T("")),Params);
  367. TRACEF("_Exec: calling CreateProcess>%s< in >%s< addedQ=%d show=%u\n",buf,sei.lpDirectory,*Q,sei.nShow);
  368. if ( !CreateProcess(0,buf,0,0,false,0,0,sei.lpDirectory,&si,&pi) ) goto die_GLE;
  369. CloseHandle(pi.hThread);
  370. sei.hProcess=pi.hProcess;
  371. }
  372. else
  373. {
  374. sei.fMask|=SEE_MASK_NOCLOSEPROCESS;
  375. TRACEF("_Exec: calling ShellExecuteEx...\n");
  376. if ( !ShellExecuteEx(&sei) )goto die_GLE;
  377. }
  378. if (Wait)
  379. {
  380. WaitForSingleObject(sei.hProcess,INFINITE);
  381. GetExitCodeProcess(sei.hProcess,&g.LastWaitExitCode);
  382. }
  383. else WaitForInputIdle(sei.hProcess,1500);//wait a little bit so the finish page window does not go away too fast and cause focus problems
  384. CloseHandle(sei.hProcess);
  385. ec=NO_ERROR;
  386. ret:
  387. if (buf)NSIS::MemFree(buf);
  388. return ec;
  389. die_GLE:
  390. ec=GetLastError();
  391. TRACEF("_Exec>%s failed with error %u (%s)\n",UseCreateProcess?"CreateProcess":"ShExec",ec,buf);
  392. goto ret;
  393. }
  394. WORD GetShowWndCmdFromStr(NSISCH*s)
  395. {
  396. //NOTE: Little used modes are still supported, just not with strings, you must use the actual number or ${SW_xx} defines from WinMessages.h
  397. struct {NSISCH*id;WORD cmd;} swcm[] = {
  398. {_T("SW_HIDE"), SW_HIDE},
  399. {_T("SW_SHOW"), SW_SHOW},
  400. {_T("SW_RESTORE"), SW_RESTORE},
  401. {_T("SW_MAXIMIZE"), SW_MAXIMIZE},
  402. {_T("SW_MINIMIZE"), SW_MINIMIZE},
  403. // {_T("SW_MAX"), SW_MAXIMIZE},
  404. // {_T("SW_MIN"), SW_MINIMIZE},
  405. {_T("SW_SHOWNORMAL"), SW_SHOWNORMAL},
  406. //{_T("SW_NORMAL"), SW_NORMAL},
  407. //{_T("SW_SHOWMINIMIZED"), SW_SHOWMINIMIZED},
  408. //{_T("SW_SHOWMAXIMIZED"), SW_SHOWMAXIMIZED},
  409. //{_T("SW_SHOWNOACTIVATE"), SW_SHOWNOACTIVATE},
  410. //{_T("SW_SHOWNA"), SW_SHOWNA},
  411. //{_T("SW_SHOWMINNOACTIVE"), SW_SHOWMINNOACTIVE},
  412. //{_T("SW_SHOWDEFAULT"), SW_SHOWDEFAULT},
  413. //{_T("SW_FORCEMINIMIZE"), SW_FORCEMINIMIZE},
  414. {0}
  415. };
  416. for (int i=0; swcm[i].id; ++i) if (StrCmpI(s,swcm[i].id)) return swcm[i].cmd;
  417. return SW_INVALID;
  418. }
  419. #define HasIPCServer() (g.UseIPC!=NULL)
  420. void HandleExecExport(bool CreateProc,bool Wait,HWND&hwndNSIS,int&StrSize,NSISCH*&Vars,stack_t**&StackTop,NSIS::extra_parameters*pXParams)
  421. {
  422. DWORD ec=NO_ERROR,ForkExitCode=ERROR_INVALID_FUNCTION;
  423. UINT cch=0,cbStruct;
  424. WORD ShowWnd;
  425. IPC_SHEXEC*pISE=0;
  426. stack_t* const pSIVerb=CreateProc?0:StackPop();//Only ShellExec supports verb's
  427. stack_t* const pSIShowWnd =StackPop();
  428. stack_t* const pSIExec =StackPop();
  429. stack_t* const pSIParams =StackPop();
  430. stack_t* const pSIWorkDir =StackPop();
  431. if (ec=MaintainDllSelfRef())goto ret;
  432. if (!pSIExec || !pSIParams || !pSIWorkDir || !pSIShowWnd || (!pSIVerb && !CreateProc))
  433. {
  434. TRACE("If you see this you probably forgot that all parameters are required!\n");
  435. ec=ERROR_INVALID_PARAMETER;
  436. goto ret;
  437. }
  438. ShowWnd=GetShowWndCmdFromStr(pSIShowWnd->text);
  439. if (ShowWnd==SW_INVALID && *pSIShowWnd->text)
  440. {
  441. BOOL BadCh;
  442. ShowWnd=StrToUInt(pSIShowWnd->text,false,&BadCh);
  443. if (BadCh)ShowWnd=SW_INVALID;
  444. }
  445. TRACEF("HandleExecExport: ipc=%X (%X)\n",g.UseIPC,g.hSrvIPC);
  446. SyncVars(hwndNSIS);
  447. if (!g.UseIPC) //No IPC Server, we are not elevated with UAC
  448. {
  449. ec=_Exec(hwndNSIS,pSIVerb?pSIVerb->text:0,pSIExec->text,pSIParams->text,pSIWorkDir->text,ShowWnd,Wait,CreateProc);
  450. if (Wait)ForkExitCode=g.LastWaitExitCode;
  451. goto ret;
  452. }
  453. cch+=lstrlen(pSIExec->text)+1;
  454. cch+=lstrlen(pSIParams->text)+1;
  455. cch+=lstrlen(pSIWorkDir->text)+1;
  456. if (pSIVerb)cch+=lstrlen(pSIVerb->text)+1;
  457. cbStruct=FIELD_OFFSET( IPC_SHEXEC, buf[cch*sizeof(TCHAR)] );
  458. pISE=(IPC_SHEXEC*)NSIS::MemAlloc(cbStruct);
  459. if (!pISE)ec=GetLastError();
  460. if (!ec)
  461. {
  462. DWORD_PTR MsgRet;
  463. pISE->hwnd =hwndNSIS;
  464. pISE->Wait =Wait;
  465. pISE->ShowMode =ShowWnd;
  466. pISE->UseCreateProcess=CreateProc;
  467. //Just offsets at this point
  468. pISE->strExec =(NSISCH*)0;
  469. pISE->strParams =(NSISCH*)(lstrlen(pSIExec->text) +pISE->strExec+1);
  470. pISE->strWorkDir=(NSISCH*)(lstrlen(pSIParams->text) +pISE->strParams+1);
  471. pISE->strVerb= (NSISCH*)(lstrlen(pSIWorkDir->text)+pISE->strWorkDir+1);
  472. lstrcpy(pISE->buf,pSIExec->text);
  473. lstrcpy(&pISE->buf[(DWORD_PTR)pISE->strParams], pSIParams->text);
  474. lstrcpy(&pISE->buf[(DWORD_PTR)pISE->strWorkDir],pSIWorkDir->text);
  475. if (pSIVerb)lstrcpy(&pISE->buf[(DWORD_PTR)pISE->strVerb], pSIVerb->text);
  476. COPYDATASTRUCT cds;
  477. cds.dwData=CDI_SHEXEC;
  478. cds.cbData=cbStruct;
  479. cds.lpData=pISE;
  480. AllowOuterInstanceWindowFocus();
  481. if (!(ec=SendIPCMsg(WM_COPYDATA,(WPARAM)hwndNSIS,(LPARAM)&cds,MsgRet,Wait?(INFINITE):(IPCTOUT_LONG) )))ec=MsgRet-1;
  482. TRACEF("HandleExecExport: IPC returned %X, ec=%d\n",MsgRet,ec);
  483. if (Wait && NO_ERROR==ec)
  484. {
  485. ec=SendIPCMsg(IPC_GETEXITCODE,0,0,ForkExitCode);
  486. TRACEF("HandleExecExport(Wait): Spawned process exit code=%d",ForkExitCode);
  487. }
  488. }
  489. ret:
  490. NSIS::MemFree(pISE);
  491. StackFreeItem(pSIShowWnd);
  492. StackFreeItem(pSIExec);
  493. StackFreeItem(pSIParams);
  494. StackFreeItem(pSIWorkDir);
  495. StackFreeItem(pSIVerb);
  496. SetVarUINT(INST_0,ec);
  497. if (ec)SetErrorFlag(pXParams);
  498. if (Wait)SetVarUINT(INST_1,ForkExitCode);
  499. }
  500. bool _SupportsUAC(bool VersionTestOnly=false)
  501. {
  502. TOKEN_ELEVATION_TYPE tet;
  503. OSVERSIONINFO ovi={sizeof(ovi)};
  504. if (!GetVersionEx(&ovi))
  505. {
  506. ASSERT(!"_SupportsUAC>GetVersionEx");
  507. return false;
  508. }
  509. if (VersionTestOnly)return ovi.dwMajorVersion>=6;
  510. if (ovi.dwMajorVersion>=6 && _GetElevationType(&tet)==NO_ERROR)
  511. {
  512. const bool ret=tet!=TokenElevationTypeDefault && tet!=NULL;
  513. TRACEF("_SupportsUAC tet=%d, returning %d\n",tet,ret);
  514. return ret;
  515. }
  516. DBGONLY(TRACEF("_SupportsUAC returning false! ver=%d _GetElevationType.ret=%u\n",ovi.dwMajorVersion,_GetElevationType(&tet)));
  517. return false;
  518. }
  519. DWORD _GetElevationType(TOKEN_ELEVATION_TYPE*pTokenElevType)
  520. {
  521. DWORD ec=ERROR_ACCESS_DENIED;
  522. HANDLE hToken=0;
  523. DWORD RetLen;
  524. if (!pTokenElevType)return ERROR_INVALID_PARAMETER;
  525. if (ec=DelayLoadDlls())return ec;
  526. *pTokenElevType=(TOKEN_ELEVATION_TYPE)NULL;
  527. if (!_SupportsUAC(true))return NO_ERROR;
  528. if (!_OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken))goto dieLastErr;
  529. if (!_GetTokenInformation(hToken,(_TOKEN_INFORMATION_CLASS)TokenElevationType,pTokenElevType,sizeof(TOKEN_ELEVATION_TYPE),&RetLen))goto dieLastErr;
  530. SetLastError(NO_ERROR);
  531. dieLastErr:
  532. ec=GetLastError();
  533. CloseHandle(hToken);
  534. TRACEF("_GetElevationType ec=%u type=%d\n",ec,*pTokenElevType);
  535. return ec;
  536. }
  537. bool _IsUACEnabled()
  538. {
  539. HKEY hKey;
  540. bool ret=false;
  541. if (GetSysVer()>=6 && NO_ERROR==RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),0,KEY_READ,&hKey))
  542. {
  543. //Check must be !=0, see http://codereview.chromium.org/3110 & http://src.chromium.org/viewvc/chrome?view=rev&revision=2330
  544. //Apparently, Vista treats !=0 as UAC on, and some machines have EnableLUA=2 !!
  545. DWORD val,type,size=sizeof(DWORD);
  546. if (NO_ERROR==RegQueryValueEx(hKey,_T("EnableLUA"),0,&type,(LPBYTE)&val,&size) && type==REG_DWORD && val!=0) ret=true;
  547. RegCloseKey(hKey);
  548. }
  549. return ret;
  550. }
  551. bool SysQuery_IsServiceRunning(LPCTSTR servicename)
  552. {
  553. bool retval=false;
  554. SC_HANDLE scdbh=NULL,hsvc;
  555. scdbh=OpenSCManager(NULL,NULL,GENERIC_READ);
  556. if (scdbh)
  557. {
  558. if (hsvc=OpenService(scdbh,servicename,SERVICE_QUERY_STATUS))
  559. {
  560. SERVICE_STATUS ss;
  561. if (QueryServiceStatus(hsvc,&ss))retval=(ss.dwCurrentState==SERVICE_RUNNING);
  562. CloseServiceHandle(hsvc);
  563. }
  564. }
  565. CloseServiceHandle(scdbh);
  566. return retval;
  567. }
  568. inline bool SysNT5IsSecondaryLogonSvcRunning()
  569. {
  570. return SysQuery_IsServiceRunning(_T("seclogon"));
  571. }
  572. bool SysElevationPresent() //Will return false on Vista if UAC is off
  573. {
  574. const DWORD vmaj=GetSysVer();
  575. ASSERT(vmaj<=6 && vmaj>=4);
  576. if (vmaj==5) return true; //TODO:Check if secondary logon service is running?
  577. if (vmaj>=6) return _IsUACEnabled();
  578. return false;
  579. }
  580. FORCEINLINE bool SysSupportsRunAs()
  581. {
  582. return GetSysVer()>=5;
  583. }
  584. bool _IsAdmin()
  585. {
  586. #ifdef BUILD_XPTEST
  587. static int _dbgOld=-1;
  588. unsigned _dbg=(unsigned)FindExePathEnd(GetCommandLine());
  589. 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);
  590. if (_dbg!=IDCANCEL){SetLastError(0);return _dbg==IDYES;}
  591. #endif
  592. BOOL isAdmin=false;
  593. DWORD ec;
  594. OSVERSIONINFO ovi={sizeof(ovi)};
  595. if (!GetVersionEx(&ovi))return false;
  596. if (VER_PLATFORM_WIN32_NT != ovi.dwPlatformId) //Not NT
  597. {
  598. SetLastError(NO_ERROR);
  599. return true;
  600. }
  601. if (ec=DelayLoadDlls())
  602. {
  603. TRACEF("DelayLoadDlls failed in _IsAdmin() with err x%X\n",ec);
  604. SetLastError(ec);
  605. return false;
  606. }
  607. ASSERT(_OpenThreadToken && _OpenProcessToken && _AllocateAndInitializeSid && _EqualSid && _FreeSid);
  608. HANDLE hToken;
  609. if (_OpenThreadToken(GetCurrentThread(),TOKEN_QUERY,FALSE,&hToken) || _OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken))
  610. {
  611. SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
  612. PSID psid=0;
  613. if (_AllocateAndInitializeSid(&SystemSidAuthority,2,SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,0,&psid))
  614. {
  615. if (_CheckTokenMembership)
  616. {
  617. if (!_CheckTokenMembership(0,psid,&isAdmin))isAdmin=false;
  618. }
  619. else
  620. {
  621. DWORD cbTokenGrps;
  622. if (!_GetTokenInformation(hToken,TokenGroups,0,0,&cbTokenGrps)&&GetLastError()==ERROR_INSUFFICIENT_BUFFER)
  623. {
  624. TOKEN_GROUPS*ptg=0;
  625. if (ptg=(TOKEN_GROUPS*)NSIS::MemAlloc(cbTokenGrps))
  626. {
  627. if (_GetTokenInformation(hToken,TokenGroups,ptg,cbTokenGrps,&cbTokenGrps))
  628. {
  629. for (UINT i=0; i<ptg->GroupCount;i++)
  630. {
  631. if (_EqualSid(ptg->Groups[i].Sid,psid))isAdmin=true;
  632. }
  633. }
  634. NSIS::MemFree(ptg);
  635. }
  636. }
  637. }
  638. _FreeSid(psid);
  639. }
  640. CloseHandle(hToken);
  641. }
  642. if (isAdmin) //UAC Admin with split token check
  643. {
  644. if (_SupportsUAC())
  645. {
  646. TOKEN_ELEVATION_TYPE tet;
  647. if (_GetElevationType(&tet) || tet==TokenElevationTypeLimited)isAdmin=false;
  648. }
  649. else SetLastError(NO_ERROR);
  650. }
  651. return FALSE != isAdmin;
  652. }
  653. LRESULT CALLBACK IPCSrvWndProc(HWND hwnd,UINT uMsg,WPARAM wp,LPARAM lp)
  654. {
  655. switch(uMsg)
  656. {
  657. case WM_DESTROY:
  658. PostQuitMessage(0);
  659. break;
  660. case WM_CLOSE:
  661. return DestroyWindow(hwnd);
  662. case WM_COPYDATA:
  663. if (lp)
  664. {
  665. const COPYDATASTRUCT*pCDS=(COPYDATASTRUCT*)lp;
  666. if (pCDS->dwData==CDI_SHEXEC && pCDS->lpData)
  667. {
  668. if ( pCDS->cbData < sizeof(IPC_SHEXEC) )break;
  669. g.LastWaitExitCode=ERROR_INVALID_FUNCTION;
  670. IPC_SHEXEC& ise=*((IPC_SHEXEC*)pCDS->lpData);
  671. SetForegroundWindow(ise.hwnd);
  672. DWORD ec=_Exec(
  673. ise.hwnd,
  674. &ise.buf[(DWORD_PTR)ise.strVerb],
  675. &ise.buf[(DWORD_PTR)ise.strExec],
  676. &ise.buf[(DWORD_PTR)ise.strParams],
  677. &ise.buf[(DWORD_PTR)ise.strWorkDir],
  678. ise.ShowMode,ise.Wait,ise.UseCreateProcess
  679. );
  680. TRACEF("IPCSrvWndProc>IPC_SHEXEC>_ShExec=%d\n",ec);
  681. return ec+1;
  682. }
  683. else if (pCDS->dwData==CDI_SYNCVAR && pCDS->lpData && pCDS->cbData>1)
  684. {
  685. IPC_SYNCVAR*pSV=(IPC_SYNCVAR*)pCDS->lpData;
  686. if (pSV->VarId>=__INST_LAST)return 1+ERROR_INVALID_PARAMETER;
  687. TRACEF("WM_COPYDATA: CDI_SYNCVAR:%d=%s|\n",pSV->VarId,&pSV->buf[0]);
  688. lstrcpy(GetVar(pSV->VarId),&pSV->buf[0]);
  689. return NO_ERROR+1;
  690. }
  691. else if (pCDS->dwData==CDI_STACKPUSH && pCDS->lpData && pCDS->cbData>=1)
  692. {
  693. TRACEF("WM_COPYDATA: CDI_STACKPUSH:%s|\n",pCDS->lpData);
  694. return StackPush((NSISCH*)pCDS->lpData)+1;
  695. }
  696. }
  697. break;
  698. case IPC_GETEXITCODE:
  699. return g.LastWaitExitCode;
  700. case IPC_ELEVATEAGAIN:
  701. TRACE("IPCSrvWndProc>IPC_ELEVATEAGAIN\n");
  702. return (g.ElevateAgain=true);
  703. case IPC_GETSRVPID:
  704. return GetCurrentProcessId();
  705. case IPC_GETSRVHWND:
  706. return GetWindowLongPtr(hwnd,GWLP_USERDATA);
  707. case IPC_EXECCODESEGMENT:
  708. return 1+(g.pXParams ? ExecuteCodeSegment(g.pXParams,wp,(HWND)lp) : ERROR_INVALID_FUNCTION);
  709. case IPC_GETOUTERPROCESSTOKEN:
  710. if (_OpenProcessToken)
  711. {
  712. HANDLE hToken,hOutToken;
  713. if (_OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hToken))
  714. {
  715. TRACEF("IPC_GETOUTERPROCESSTOKEN: hToken=%X targetProcess=%X\n",hToken,g.hElevatedProcess);
  716. if (DuplicateHandle(GetCurrentProcess(),hToken,g.hElevatedProcess,&hOutToken,lp,false,DUPLICATE_CLOSE_SOURCE))
  717. {
  718. TRACEF("IPC_GETOUTERPROCESSTOKEN: %X(%X) > %X(%X)\n",hToken,-1,hOutToken,g.hElevatedProcess);
  719. return (LRESULT)hOutToken;
  720. }
  721. }
  722. }
  723. return NULL;
  724. #ifdef UAC_HACK_FGWND1
  725. case IPC_HACKFINDRUNAS: //super ugly hack to get title of run as dialog
  726. if (wp<200)
  727. {
  728. HWND hRA=GetLastActivePopup((HWND)lp);
  729. TRACEF("IPC_HACKFINDRUNAS:%d %X %X\n",wp,lp,hRA);
  730. if (hRA && hRA !=(HWND)lp ) return PostMessage((HWND)lp,WM_APP,0,(LONG_PTR)hRA);
  731. Sleep(10);PostMessage(hwnd,uMsg,wp+1,lp);
  732. }
  733. break;
  734. #endif
  735. }
  736. return DefWindowProc(hwnd,uMsg,wp,lp);
  737. }
  738. DWORD WINAPI IPCSrvThread(LPVOID lpParameter)
  739. {
  740. CoInitialize(0);
  741. const DWORD WStyle=WS_VISIBLE DBGONLY(|(WS_CAPTION));
  742. const int PosOffset=32700;
  743. MSG msg;
  744. WNDCLASS wc={0};
  745. wc.lpszClassName=GetIPCWndClass();
  746. wc.lpfnWndProc=IPCSrvWndProc;
  747. wc.hInstance=g.hInstance;
  748. if (!RegisterClass(&wc))goto dieLastErr;
  749. if (!(g.hSrvIPC=CreateWindowEx(WS_EX_TOOLWINDOW DBGONLY(&~WS_EX_TOOLWINDOW),
  750. GetIPCWndClass(),
  751. DBGONLY(_T("Debug: NSIS.UAC")+)0,
  752. WStyle,
  753. -PosOffset DBGONLY(+PosOffset),-PosOffset DBGONLY(+PosOffset),DBGONLY(150+)1,DBGONLY(10+)1,
  754. 0,0,wc.hInstance,0
  755. )))goto dieLastErr;
  756. SetWindowLongPtr(g.hSrvIPC,GWLP_USERDATA,(LONG_PTR)lpParameter);
  757. TRACEF("IPCSrv=%X server created...\n",g.hSrvIPC);
  758. while (GetMessage(&msg,0,0,0)>0)DispatchMessage(&msg);
  759. SetLastError(NO_ERROR);
  760. dieLastErr:
  761. CoUninitialize();
  762. return g.LastWaitExitCode=GetLastError();
  763. }
  764. DWORD InitIPC(HWND hwndNSIS,NSIS::extra_parameters*pXParams,UINT NSISStrLen)
  765. {
  766. if (g.threadIPC)return NO_ERROR;
  767. TRACEF("InitIPC StrSize=%u vs %u\n",NSIS::StrSize,NSISStrLen);
  768. DWORD tid;
  769. ASSERT(!g.pXParams && pXParams);
  770. ASSERT(NSISStrLen>0 && NSISStrLen==NSIS::StrSize);
  771. g.NSISStrLen=NSISStrLen;
  772. g.pXParams=pXParams;
  773. g.threadIPC=CreateThread(0,0,IPCSrvThread,hwndNSIS,0,&tid);
  774. if (g.threadIPC)
  775. {
  776. while(!g.hSrvIPC && !g.LastWaitExitCode)Sleep(20);
  777. return g.hSrvIPC ? NO_ERROR : g.LastWaitExitCode;
  778. }
  779. return GetLastError();
  780. }
  781. void StopIPCSrv()
  782. {
  783. if (g.threadIPC)
  784. {
  785. TRACEF("StopIPCSrv h=%X \n",g.hSrvIPC);
  786. #ifdef UAC_HACK_Clammerz
  787. if ( GetSysVer()>=5 )
  788. {
  789. //WINBUGFIX: This ugly thing supposedly solves the problem of messagebox'es in .OnInit appearing behind other windows in Vista
  790. HWND hack=CreateWindowEx(WS_EX_TRANSPARENT|WS_EX_LAYERED,_T("Button"),NULL,NULL,0,0,0,0,NULL,NULL,NULL,0);
  791. ShowWindow(hack,SW_SHOW);
  792. SetForegroundWindow(hack);
  793. DestroyWindow(hack);
  794. }
  795. #endif
  796. PostMessage(g.hSrvIPC,WM_CLOSE,0,0);
  797. WaitForSingleObject(g.threadIPC,INFINITE);
  798. CloseHandle(g.threadIPC);
  799. UnregisterClass(GetIPCWndClass(),g.hInstance);//DLL can be loaded more than once, so make sure RegisterClass doesn't fail
  800. g.hSrvIPC=0;
  801. g.threadIPC=0;
  802. }
  803. }
  804. #ifdef UAC_HACK_FGWND1
  805. LRESULT CALLBACK HackWndSubProc(HWND hwnd,UINT Msg,WPARAM wp,LPARAM lp)
  806. {
  807. switch(Msg)
  808. {
  809. case WM_APP:
  810. GetWindowText((HWND)lp,GetVar(0),NSIS::StrSize);
  811. if (*GetVar(0))SendMessage(hwnd,WM_SETTEXT,0,(LONG_PTR)GetVar(0));
  812. break;
  813. }
  814. return DefWindowProc(hwnd,Msg,wp,lp);
  815. }
  816. #endif
  817. inline bool MustUseInternalRunAs()
  818. {
  819. #ifdef BUILD_DBGSELECTELVMODE
  820. TCHAR dbgb[MAX_PATH*4];wsprintf(dbgb,_T("%s.ini"),GetVar(VIDX_EXEPATH));
  821. static int dbg_answer=GetPrivateProfileInt(_T("UACDBG"),_T("MustUseInternalRunAs"),2,dbgb);
  822. if (dbg_answer<2)return !!dbg_answer;WritePrivateProfileString(_T("UACDBG"),_T("MustUseInternalRunAs"),"",dbgb);
  823. if (MessageBox(GetActiveWindow(),"MustUseInternalRunAs?",dbgb,MB_YESNO)==IDYES)return true;
  824. #endif
  825. return GetSysVer()>=6 && !SysElevationPresent();
  826. }
  827. DWORD ForkSelf(HWND hParent,DWORD&ForkExitCode,NSIS::extra_parameters*pXParams,UINT NSISStrLen)
  828. {
  829. DWORD ec=ERROR_ACCESS_DENIED;
  830. SHELLEXECUTEINFO sei={sizeof(sei)};
  831. //STARTUPINFO startInfo={sizeof(STARTUPINFO)};
  832. LPTSTR pszExePathBuf=0;
  833. LPTSTR pszParamBuf=0;
  834. LPTSTR p,pCL=GetCommandLine();
  835. UINT len;
  836. const OSVerMaj=GetOSVerMaj();
  837. #ifdef UAC_HACK_FGWND1
  838. HWND hHack=0;
  839. #endif
  840. ASSERT(pXParams);
  841. //GetStartupInfo(&startInfo);
  842. if (ec=InitIPC(hParent,pXParams,NSISStrLen))goto ret;
  843. ASSERT(IsWindow(g.hSrvIPC));
  844. sei.hwnd=hParent;
  845. sei.nShow=/*(startInfo.dwFlags&STARTF_USESHOWWINDOW) ? startInfo.wShowWindow :*/ SW_SHOWNORMAL;
  846. sei.fMask=SEE_MASK_NOCLOSEPROCESS|SEE_MASK_NOZONECHECKS;
  847. sei.lpVerb=_T("runas");
  848. p=FindExePathEnd(pCL);
  849. len=p-pCL;
  850. if (!p || !len)
  851. {
  852. ec=ERROR_FILE_NOT_FOUND;
  853. goto ret;
  854. }
  855. for (;;)
  856. {
  857. NSIS::MemFree(pszExePathBuf);
  858. if (!(pszExePathBuf=(LPTSTR)NSIS::MemAlloc((++len)*sizeof(TCHAR))))goto dieOOM;
  859. if ( GetModuleFileName(0,pszExePathBuf,len) < len )break; //FUCKO: what if GetModuleFileName returns 0?
  860. len+=MAX_PATH;
  861. }
  862. sei.lpFile=pszExePathBuf;
  863. len=lstrlen(p);
  864. len+=20;//space for "/UAC:xxxxxx /NCRC\0"
  865. if (!(pszParamBuf=(LPTSTR)NSIS::MemAlloc(len*sizeof(TCHAR))))goto dieOOM;
  866. wsprintf(pszParamBuf,_T("/UAC:%X /NCRC%s"),g.hSrvIPC,p);//NOTE: The argument parser depends on our special flag appearing first
  867. sei.lpParameters=pszParamBuf;
  868. if (OSVerMaj==5)
  869. {
  870. bool hasseclogon=SysNT5IsSecondaryLogonSvcRunning();
  871. TRACEF("SysNT5IsSecondaryLogonSvcRunning=%d\n",hasseclogon);
  872. if (!hasseclogon)
  873. {
  874. ec=ERROR_SERVICE_NOT_ACTIVE;
  875. goto ret;
  876. }
  877. }
  878. #ifdef UAC_HACK_FGWND1
  879. if ( OSVerMaj>=5 && !sei.hwnd )
  880. {
  881. //sei.nShow=SW_SHOW;//forced, do we HAVE to do this?
  882. 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);
  883. SetWindowLongPtr(hHack,GWLP_WNDPROC,(LONG_PTR)HackWndSubProc);
  884. if (GetSysVer()<6 || MustUseInternalRunAs())
  885. PostMessage(g.hSrvIPC,IPC_HACKFINDRUNAS,0,(LONG_PTR)hHack);
  886. else
  887. SetWindowLongPtr(hHack,GWL_EXSTYLE,GetWindowLongPtr(hHack,GWL_EXSTYLE)&~WS_EX_APPWINDOW);//kill taskbar btn on vista
  888. HICON hIcon=(HICON)LoadImage(GetModuleHandle(0),MAKEINTRESOURCE(103),IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_SHARED);
  889. SendMessage(hHack,WM_SETICON,ICON_BIG,(LONG_PTR)hIcon);
  890. ShowWindow(hHack,SW_SHOW);
  891. SetForegroundWindow(hHack);
  892. sei.hwnd=hHack;
  893. }
  894. #endif
  895. if (hParent)SetForegroundWindow(hParent);//try to force taskbar button active (for RunElevatedAndProcessMessages, really important on Vista)
  896. #ifdef FEAT_CUSTOMRUNASDLG
  897. if (MustUseInternalRunAs())
  898. {
  899. ec=MyRunAs(g.hInstance,sei);
  900. }
  901. else
  902. #endif
  903. {
  904. if (GetSysVer()>=6)
  905. {
  906. ////////sei.nShow=SW_SHOW;
  907. //if ( _SupportsUAC() )sei.hwnd=0; //Vista does not like it when we provide a HWND
  908. //if (_AllowSetForegroundWindow) _AllowSetForegroundWindow(ASFW_ANY);//TODO: is GrantClientWindowInput() enough?
  909. }
  910. #ifdef FEAT_MSRUNASDLGMODHACK
  911. void* hook=MSRunAsDlgMod_Init();
  912. #endif
  913. TRACEF("ForkSelf:calling ShExec:app=%s|params=%s|vrb=%s|hwnd=%X\n",sei.lpFile,sei.lpParameters,sei.lpVerb,sei.hwnd);
  914. ec=(ShellExecuteEx(&sei)?NO_ERROR:GetLastError());
  915. TRACEF("ForkSelf: ShExec->Runas returned %d hInstApp=%d\n",ec,sei.hInstApp);
  916. #ifdef FEAT_MSRUNASDLGMODHACK
  917. MSRunAsDlgMod_Unload(hook);
  918. #endif
  919. }
  920. #ifdef UAC_HACK_FGWND1
  921. DestroyWindow(hHack);
  922. #endif
  923. if (ec)goto ret;
  924. TRACEF("ForkSelf: waiting for process %X (%s|%s|%s)sei.hwnd=%X\n",(sei.hProcess),sei.lpFile,sei.lpParameters,sei.lpVerb,sei.hwnd);
  925. ASSERT(sei.hProcess);
  926. ASSERT(NO_ERROR==ec);
  927. ShowWindow(g.hSrvIPC,SW_HIDE);
  928. g.hElevatedProcess=sei.hProcess;
  929. if (!IsWindow(sei.hwnd))
  930. {
  931. DWORD w=WaitForSingleObject(sei.hProcess,INFINITE);
  932. if (w==WAIT_OBJECT_0)
  933. VERIFY(GetExitCodeProcess(sei.hProcess,&ForkExitCode));
  934. else
  935. {
  936. ec=GetLastError();
  937. TRACEF("ForkSelf:WaitForSingleObject failed ec=%d w=%d\n",ec,w);ASSERT(!"ForkSelf:WaitForSingleObject");
  938. }
  939. }
  940. else
  941. {
  942. bool abortWait=false;
  943. const DWORD waitCount=1;
  944. const HANDLE handles[waitCount]={sei.hProcess};
  945. do
  946. {
  947. DWORD w=MsgWaitForMultipleObjects(waitCount,handles,false,INFINITE,QS_ALLEVENTS|QS_ALLINPUT);
  948. switch(w)
  949. {
  950. case WAIT_OBJECT_0:
  951. VERIFY(GetExitCodeProcess(sei.hProcess,&ForkExitCode));
  952. abortWait=true;
  953. break;
  954. case WAIT_OBJECT_0+waitCount:
  955. {
  956. const HWND hwnd=sei.hwnd;
  957. MSG msg;
  958. while( !ec && PeekMessage(&msg,hwnd,0,0,PM_REMOVE) )
  959. {
  960. if (msg.message==WM_QUIT)
  961. {
  962. ASSERT(0);
  963. ec=ERROR_CANCELLED;
  964. break;
  965. }
  966. if (!IsDialogMessage(hwnd,&msg))
  967. {
  968. TranslateMessage(&msg);
  969. DispatchMessage(&msg);
  970. }
  971. }
  972. }
  973. break;
  974. default:
  975. abortWait=true;
  976. ec=GetLastError();
  977. TRACEF("ForkSelf:MsgWaitForMultipleObjects failed, ec=%u w=%u\n",ec,w);
  978. }
  979. } while( NO_ERROR==ec && !abortWait );
  980. }
  981. TRACEF("ForkSelf: wait complete, ec=%d forkexitcode=%u\n",ec,ForkExitCode);
  982. goto ret;
  983. dieOOM:
  984. ec=ERROR_OUTOFMEMORY;
  985. ret:
  986. StopIPCSrv();
  987. CloseHandle(sei.hProcess);
  988. NSIS::MemFree(pszExePathBuf);
  989. NSIS::MemFree(pszParamBuf);
  990. return ec;
  991. }
  992. bool GetIPCSrvWndFromParams(HWND&hwndOut)
  993. {
  994. LPTSTR p=FindExePathEnd(GetCommandLine());
  995. while(p && *p==' ')p=CharNext(p);TRACEF("GetIPCSrvWndFromParams:%s|\n",p);
  996. if (p && *p++=='/'&&*p++=='U'&&*p++=='A'&&*p++=='C'&&*p++==':')
  997. {
  998. hwndOut=(HWND)StrToUInt(p,true);
  999. return !!IsWindow(hwndOut);
  1000. }
  1001. return false;
  1002. }
  1003. /*** RunElevated
  1004. Return: r0: Windows error code (0 on success, 1223 if user aborted elevation dialog, anything else should be treated as a fatal error)
  1005. r1: If r0==0, r1 is:
  1006. 0 if UAC is not supported by the OS,
  1007. 1 if UAC was used to elevate and the current process should act like a wrapper (Call Quit in .OnInit without any further processing),
  1008. 2 if the process is (already?) running @ HighIL (Member of admin group on other systems),
  1009. 3 if you should call RunElevated again (This can happen if a user without admin priv. is used in the runas dialog),
  1010. r2: If r0==0 && r1==1: r2 is the ExitCode of the elevated fork process (The NSIS errlvl is also set to the ExitCode)
  1011. r3: If r0==0: r3 is 1 if the user is a member of the admin group or 0 otherwise
  1012. */
  1013. EXPORTNSISFUNC RunElevated(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1014. {
  1015. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1016. BYTE UACMode=0;
  1017. bool UserIsAdmin=false;
  1018. DWORD ec=ERROR_ACCESS_DENIED,ForkExitCode;
  1019. TOKEN_ELEVATION_TYPE tet;
  1020. UserIsAdmin=_IsAdmin();
  1021. TRACEF("RunElevated:Init: IsAdmin=%d\n",UserIsAdmin);
  1022. #ifdef BUILD_XPTEST
  1023. if (!UserIsAdmin)goto DbgXPAsUAC;//Skip UAC detection for special debug builds and force a call to runas on <NT6 systems
  1024. #endif
  1025. if (!_SupportsUAC() && !SysSupportsRunAs())goto noUAC;
  1026. if ((ec=DelayLoadDlls()))goto ret;
  1027. if (GetIPCSrvWndFromParams(g.hSrvIPC))
  1028. {
  1029. if (ec=DllSelfAddRef())goto ret;
  1030. if (!IsWindow(g.hSrvIPC))ec=ERRAPP_BADIPCSRV;
  1031. UACMode=2;
  1032. g.UseIPC=true;
  1033. if (!UserIsAdmin) //Elevation used, but we are not Admin, let the wrapper know so it can try again...
  1034. {
  1035. UACMode=0xFF;//Special invalid mode
  1036. DWORD_PTR MsgRet;
  1037. if (SendIPCMsg(IPC_ELEVATEAGAIN,0,0,MsgRet) || !MsgRet)ec=ERRAPP_BADIPCSRV;//if we could not notify the need for re-elevation, the IPCSrv must be bad
  1038. }
  1039. goto ret;
  1040. }
  1041. if ( (ec=DllSelfAddRef()) || (ec=_GetElevationType(&tet)) )goto ret;
  1042. if ( tet==TokenElevationTypeFull || UserIsAdmin )
  1043. {
  1044. UserIsAdmin=true;
  1045. UACMode=2;
  1046. goto ret;
  1047. }
  1048. DBGONLY(DBG_RESETDBGVIEW());
  1049. #ifdef BUILD_XPTEST
  1050. DbgXPAsUAC:VERIFY(!DllSelfAddRef());
  1051. #endif
  1052. //OS supports UAC and we need to elevate...
  1053. ASSERT(!UserIsAdmin);
  1054. UACMode=1;
  1055. ec=ForkSelf(hwndNSIS,ForkExitCode,XParams,StrSize);
  1056. if (!ec && !g.ElevateAgain)
  1057. {
  1058. SetVarUINT(INST_2,ForkExitCode);
  1059. SetErrLvl(XParams,ForkExitCode);
  1060. }
  1061. goto ret;
  1062. noUAC:
  1063. ec=NO_ERROR;ASSERT(UACMode==0);
  1064. ret:
  1065. if (ec==ERROR_CANCELLED)
  1066. {
  1067. if (UACMode!=1)ec=ERROR_INVALID_FUNCTION;
  1068. if (UACMode<2)g.UseIPC=false;
  1069. }
  1070. if (UACMode==0xFF && !ec) //We called IPC_ELEVATEAGAIN, so we need to quit so the wrapper gains control
  1071. {
  1072. ASSERT(g.UseIPC);
  1073. UACMode=1;//We pretend to be the wrapper so Quit gets called in .OnInit
  1074. SetErrLvl(XParams,0);
  1075. _Unload();
  1076. }
  1077. if (g.ElevateAgain)
  1078. {
  1079. ASSERT(!g.UseIPC);
  1080. UACMode=3;//Fork called IPC_ELEVATEAGAIN, we need to change our UACMode so the wrapper(our instance) can try to elevate again if it wants to
  1081. }
  1082. if (!g.UseIPC)
  1083. _Unload();//The wrapper can call quit in .OnInit without calling UAC::Unload, so we do it here
  1084. SetVarUINT(INST_0,ec);
  1085. SetVarUINT(INST_1,UACMode);
  1086. SetVarUINT(INST_3,UserIsAdmin);
  1087. TRACEF("RunElevated returning ec=%X UACMode=%d g.UseIPC=%d g.ElevateAgain=%d IsAdmin=%d\n",ec,UACMode,g.UseIPC,g.ElevateAgain,UserIsAdmin);
  1088. NSISFUNCEND();
  1089. }
  1090. /*** Exec
  1091. Notes:
  1092. ¤ ErrorFlag is also set on error
  1093. STACK: <ShowWindow> <File> <Parameters> <WorkingDir>
  1094. Return: windows error code in r0, 0 on success
  1095. */
  1096. EXPORTNSISFUNC Exec(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1097. {
  1098. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1099. HandleExecExport(true,false,hwndNSIS,StrSize,Vars,StackTop,XParams);
  1100. NSISFUNCEND();
  1101. }
  1102. /*** ExecWait
  1103. Notes:
  1104. ¤ ErrorFlag is also set on error
  1105. STACK: <ShowWindow> <File> <Parameters> <WorkingDir>
  1106. Return:
  1107. r0: windows error code, 0 on success
  1108. r1: exitcode of new process
  1109. */
  1110. EXPORTNSISFUNC ExecWait(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1111. {
  1112. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1113. HandleExecExport(true,true,hwndNSIS,StrSize,Vars,StackTop,XParams);
  1114. NSISFUNCEND();
  1115. }
  1116. /*** ShellExec
  1117. Notes:
  1118. ¤ ErrorFlag is also set on error
  1119. STACK: <Verb> <ShowWindow> <File> <Parameters> <WorkingDir>
  1120. Return: windows error code in r0, 0 on success
  1121. */
  1122. EXPORTNSISFUNC ShellExec(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1123. {
  1124. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1125. HandleExecExport(false,false,hwndNSIS,StrSize,Vars,StackTop,XParams);
  1126. NSISFUNCEND();
  1127. }
  1128. /*** ShellExecWait
  1129. Notes:
  1130. ¤ ErrorFlag is also set on error
  1131. STACK: <Verb> <ShowWindow> <File> <Parameters> <WorkingDir>
  1132. Return:
  1133. r0: windows error code, 0 on success
  1134. r1: exitcode of new process
  1135. */
  1136. EXPORTNSISFUNC ShellExecWait(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1137. {
  1138. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1139. HandleExecExport(false,true,hwndNSIS,StrSize,Vars,StackTop,XParams);
  1140. NSISFUNCEND();
  1141. }
  1142. /*** GetElevationType
  1143. Notes:
  1144. TokenElevationTypeDefault=1 :User is not using a split token (UAC disabled)
  1145. TokenElevationTypeFull=2 :UAC enabled, the process is elevated
  1146. TokenElevationTypeLimited=3 :UAC enabled, the process is not elevated
  1147. Return: r0: (TOKEN_ELEVATION_TYPE)TokenType, The error flag is set if the function fails and r0==0
  1148. */
  1149. EXPORTNSISFUNC GetElevationType(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1150. {
  1151. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1152. TOKEN_ELEVATION_TYPE tet=(TOKEN_ELEVATION_TYPE)NULL; //Default to invalid value
  1153. if (MaintainDllSelfRef() || /*!_SupportsUAC() ||*/ _GetElevationType(&tet)) SetErrorFlag(XParams);
  1154. SetVarUINT(INST_0,tet);
  1155. NSISFUNCEND();
  1156. }
  1157. /*** SupportsUAC
  1158. Notes: Check if the OS supports UAC (And the user has UAC turned on)
  1159. Return: r0: (BOOL)Result
  1160. */
  1161. EXPORTNSISFUNC SupportsUAC(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1162. {
  1163. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1164. BOOL present=false;
  1165. MaintainDllSelfRef();
  1166. if (_SupportsUAC())present=true;
  1167. SetVarUINT(INST_0,present);
  1168. NSISFUNCEND();
  1169. }
  1170. /*** IsAdmin
  1171. Return: r0: (BOOL)Result
  1172. */
  1173. EXPORTNSISFUNC IsAdmin(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1174. {
  1175. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1176. bool Admin=false;
  1177. DWORD ec;
  1178. if ( !(ec=MaintainDllSelfRef()) )
  1179. {
  1180. Admin=_IsAdmin();
  1181. if ( ec=GetLastError() )
  1182. {
  1183. TRACEF("IsAdmin failed with %d\n",ec);
  1184. SetErrorFlag(XParams);
  1185. Admin=false;
  1186. }
  1187. }
  1188. SetVarUINT(INST_0,Admin);
  1189. NSISFUNCEND();
  1190. }
  1191. /*** ExecCodeSegment
  1192. Notes: Sets error flag on error
  1193. There is currently no way to transfer state to/from the executed code segment!
  1194. 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!
  1195. */
  1196. EXPORTNSISFUNC ExecCodeSegment(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1197. {
  1198. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1199. DWORD ec;
  1200. if (!(ec=DllSelfAddRef())) //force AddRef since our plugin could be called inside the executed code segment!
  1201. {
  1202. ec=ERROR_INVALID_PARAMETER;
  1203. stack_t* pSI=StackPop();
  1204. if (pSI)
  1205. {
  1206. BOOL badCh;
  1207. UINT pos=StrToUInt(pSI->text,false,&badCh);
  1208. TRACEF("ExecCodeSegment %d (%s) badinput=%d\n",pos-1,pSI->text,badCh);
  1209. if (!badCh && pos--)
  1210. {
  1211. if (!g.UseIPC)
  1212. ec=NSIS::ExecuteCodeSegment(XParams,pos);
  1213. else
  1214. {
  1215. SyncVars(hwndNSIS);
  1216. DWORD_PTR MsgRet;
  1217. AllowOuterInstanceWindowFocus();
  1218. if (!(ec=SendIPCMsg(IPC_EXECCODESEGMENT,pos,0,MsgRet,INFINITE)))ec=MsgRet-1;
  1219. }
  1220. }
  1221. StackFreeItem(pSI);
  1222. }
  1223. }
  1224. if (ec)SetErrorFlag(XParams);
  1225. NSISFUNCEND();
  1226. }
  1227. /*** StackPush */
  1228. EXPORTNSISFUNC StackPush(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1229. {
  1230. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1231. DWORD ec;
  1232. if (!(ec=DllSelfAddRef()) && g.UseIPC)
  1233. {
  1234. stack_t* pSI=StackPop();
  1235. ec=ERROR_INVALID_PARAMETER;
  1236. if (pSI)
  1237. {
  1238. DWORD_PTR MsgRet;
  1239. COPYDATASTRUCT cds={CDI_STACKPUSH,(lstrlen(pSI->text)+1)*sizeof(NSISCH),pSI->text};
  1240. if (!(ec=SendIPCMsg(WM_COPYDATA,(WPARAM)hwndNSIS,(LPARAM)&cds,MsgRet,5000 )))ec=MsgRet-1;
  1241. StackFreeItem(pSI);
  1242. }
  1243. }
  1244. if (ec)SetErrorFlag(XParams);
  1245. NSISFUNCEND();
  1246. }
  1247. /*** GetOuterHwnd */
  1248. EXPORTNSISFUNC GetOuterHwnd(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1249. {
  1250. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1251. MaintainDllSelfRef();
  1252. DWORD_PTR MsgRet;HWND hSrvIPC;
  1253. if (!GetIPCSrvWndFromParams(hSrvIPC)||!IsWindow(hSrvIPC)||SendIPCMsg(IPC_GETSRVHWND,0,0,MsgRet,IPCTOUT_DEF,hSrvIPC))MsgRet=0;
  1254. SetVarUINT(INST_0,MsgRet);
  1255. NSISFUNCEND();
  1256. }
  1257. DWORD SetPrivilege(LPCSTR PrivName,bool Enable)
  1258. {
  1259. DWORD r=NO_ERROR;
  1260. HANDLE hToken=NULL;
  1261. TOKEN_PRIVILEGES TokenPrivs;
  1262. if (!LookupPrivilegeValueA(NULL,PrivName,&TokenPrivs.Privileges[0].Luid))goto dieGLE;
  1263. if (!_OpenProcessToken(GetCurrentProcess (),TOKEN_ADJUST_PRIVILEGES,&hToken))goto dieGLE;
  1264. TokenPrivs.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0 ;
  1265. TokenPrivs.PrivilegeCount=1;
  1266. if (AdjustTokenPrivileges(hToken,FALSE,&TokenPrivs,0,NULL,NULL))goto ret;
  1267. dieGLE:
  1268. r=GetLastError();
  1269. ret:
  1270. CloseHandle(hToken);
  1271. return r;
  1272. }
  1273. #include <shlobj.h>
  1274. /*** GetShellFolderPath */
  1275. EXPORTNSISFUNC GetShellFolderPath(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1276. {
  1277. /*
  1278. WINBUG:
  1279. For some reason, even with debug priv. enabled, a call to OpenProcessToken(TOKEN_READ|TOKEN_IMPERSONATE)
  1280. will fail, even if we have a PROCESS_ALL_ACCESS handle on XP when running as a member of the Power Users Group.
  1281. So we have to ask the outer process to give us the handle.
  1282. */
  1283. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1284. MaintainDllSelfRef();
  1285. const unsigned TokenAccessRights=TOKEN_READ|TOKEN_IMPERSONATE;
  1286. unsigned clsidFolder;
  1287. HWND hSrvIPC;
  1288. HANDLE hToken=NULL,hOuterProcess=NULL;
  1289. DWORD SrvPID;
  1290. HRESULT hr;
  1291. FARPROC pfnSHGetFolderPath;
  1292. LPTSTR buf=GetVar(INST_0);
  1293. stack_t*pssCLSID=StackPop();
  1294. stack_t*pssFallback=NULL;
  1295. BOOL ConvBadCh;
  1296. if (!pssCLSID || !(pssFallback=StackPop())) goto fail;
  1297. clsidFolder=StrToUInt(pssCLSID->text,false,&ConvBadCh);
  1298. if (ConvBadCh)goto fail;
  1299. TRACEF("GetShellFolderPath HasIPCServer=%X param=%s>%X fallback=%s|\n",HasIPCServer(),pssCLSID->text,clsidFolder,pssFallback->text);
  1300. pfnSHGetFolderPath=GetProcAddress(GetModuleHandle(_T("SHELL32")),"SHGetFolderPath"__DLD_FUNCSUFFIX);
  1301. if (!pfnSHGetFolderPath)goto fail;
  1302. if (GetIPCSrvWndFromParams(hSrvIPC) && 0 != GetWindowThreadProcessId(hSrvIPC,&SrvPID))
  1303. {
  1304. hOuterProcess=OpenProcess(PROCESS_QUERY_INFORMATION,false,SrvPID);
  1305. if (hOuterProcess)
  1306. {
  1307. BOOL bOk=OpenProcessToken(hOuterProcess,TokenAccessRights,&hToken);
  1308. CloseHandle(hOuterProcess);
  1309. if (bOk)goto gotToken;
  1310. }
  1311. /* SetPrivilege(SE_DEBUG_NAME,true);
  1312. hOuterProcess=OpenProcess(PROCESS_DUP_HANDLE,false,SrvPID);
  1313. SetPrivilege(SE_DEBUG_NAME,false);
  1314. if (!hOuterProcess)goto fail;
  1315. TRACEF("hOuterProcess=%X\n",hOuterProcess);
  1316. */ SendIPCMsg(IPC_GETOUTERPROCESSTOKEN,0,TokenAccessRights,(DWORD_PTR&)hToken,IPCTOUT_DEF,hSrvIPC);
  1317. TRACEF("IPC_GETOUTERPROCESSTOKEN=%X\n",hToken);//*/
  1318. }
  1319. gotToken:
  1320. if (HasIPCServer() && !hToken)goto fail;
  1321. hr=((HRESULT(WINAPI*)(HWND,int,HANDLE,DWORD,LPTSTR))pfnSHGetFolderPath)(hwndNSIS,clsidFolder,hToken,SHGFP_TYPE_CURRENT,buf);
  1322. TRACEF("SHGetFolderPath hr=%X with token=%X, clsidFolder=%X|%s\n",hr,hToken,clsidFolder,buf);
  1323. if (FAILED(hr)) goto fail; else goto ret;
  1324. fail:
  1325. TRACEF("GetShellFolderPath GLE=%X\n",GetLastError());
  1326. lstrcpy(buf,pssFallback->text);
  1327. TRACEF("%s|%s\n",buf,pssFallback->text);
  1328. ret:
  1329. // CloseHandle(hOuterProcess);
  1330. CloseHandle(hToken);
  1331. StackFreeItem(pssFallback);
  1332. StackFreeItem(pssCLSID);
  1333. NSISFUNCEND();
  1334. }
  1335. /*** GetOuterPID * /
  1336. EXPORTNSISFUNC GetOuterPID(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop,NSIS::extra_parameters* XParams)
  1337. {
  1338. NSISFUNCSTART(hwndNSIS,StrSize,Vars,StackTop,XParams);
  1339. MaintainDllSelfRef();
  1340. DWORD_PTR Ret=0;
  1341. HWND hSrvIPC;
  1342. if (GetIPCSrvWndFromParams(hSrvIPC))
  1343. if (0==GetWindowThreadProcessId(hSrvIPC,&Ret))Ret=0;
  1344. SetVarUINT(INST_0,Ret);
  1345. NSISFUNCEND();
  1346. }//*/
  1347. /*** Unload
  1348. Notes: Call in .OnInstFailed AND .OnInstSuccess !
  1349. */
  1350. EXPORTNSISFUNC Unload(HWND hwndNSIS,int StrSize,NSISCH*Vars,NSIS::stack_t **StackTop)
  1351. {
  1352. NSISFUNCSTART4(hwndNSIS,StrSize,Vars,StackTop);
  1353. if (!MaintainDllSelfRef())_Unload(); else ASSERT(!"MaintainDllSelfRef failed in Unload!");
  1354. NSISFUNCEND();
  1355. }
  1356. #ifdef _DEBUG
  1357. BOOL WINAPI DllMain(HINSTANCE hInst,DWORD Event,LPVOID lpReserved)
  1358. #else
  1359. extern "C" BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst,ULONG Event,LPVOID lpReserved)
  1360. #endif
  1361. {
  1362. if (Event==DLL_PROCESS_ATTACH)
  1363. {
  1364. TRACEF("************************************ DllMain %u\n",GetCurrentProcessId());
  1365. ASSERT(!_OpenProcessToken && !_EqualSid);
  1366. g.hInstance=hInst;
  1367. }
  1368. // 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
  1369. return TRUE;
  1370. }