UAC plug-in: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
No edit summary
(→‎Info: Added link)
 
(80 intermediate revisions by 18 users not shown)
Line 1: Line 1:
==Download & Info==
{{PageAuthor|Anders}}
This plug-in attempts to work around the UAC problems on Vista related to staring a new process from an elevated installer.
[[Category:Plugins]]
[[Category:Deprecated]]


It all started in http://forums.winamp.com/showthread.php?s=&threadid=265780 and is still very much in the alpha stage (Use at your own risk).
<div style="border: 1px solid #404000; background-color:#FFFF80; color:#000; padding:0.5em;"><b>Note:</b>This plug-in is deprecated. It started out as a proof of concept in the early Vista days and should now be considered abandoned.</div>


Latest version:
[http://stashbox.org/19998/UAC%20v0.0.5e.zip UAC v0.0.5e]


==Plugin Info==
* '''Version:''' 0.2.4c (20150526)
* '''Type:''' Runtime plugin
* '''Character encoding:''' Ansi
* '''Minimum OS:''' Win95/NT4 (Elevation on Win2000+)
* '''Minimum NSIS Version:''' 2.45
* '''License:''' zlib
* '''Download:''' <attach>UAC.zip</attach>


===How it works===


This plugin works through the following:
==Info==
This plug-in attempts to work around UAC installation problems on Win2000+.  This plug-in allows your installer to operate with a user level process and an admin level process ([https://docs.microsoft.com/en-us/windows/win32/secauthz/administrator-broker-model administrator broker model]).  This allows you to accomplish things that would otherwise be very difficult.  For example, you can have an elevated installer instance launch another process as the user.


* First, the NSIS script must specify that it should run with user privileges, not admin privileges.
It all started in [http://forums.winamp.com/showthread.php?s=&threadid=265780 this thread].  It has been field tested with good results.  It is still definitely in the beta stage (i.e. use at your own risk).


<pre>
==Basic Example==
RequestExecutionLevel user    /* RequestExecutionLevel REQUIRED! */
<highlight-nsis>
</pre>
/*
* Next, the most common approach is to let the UAC plugin initialize in the .onInit code:
Basic script for a all users/shared installer.
<pre>
It runs the installed application as the correct user...
;Set up our UAC to give us a user process and an admin process.
*/
Function .OnInit


UAC_Elevate:
!define S_NAME "UAC_Basic example"
    UAC::RunElevated
Name "${S_NAME}"
    StrCmp 1223 $0 UAC_ElevationAborted ; UAC dialog aborted by user?
OutFile "${S_NAME}.exe"
    StrCmp 0 $0 0 UAC_Err ; Error?
RequestExecutionLevel user ; << Required, you cannot use admin!
    StrCmp 1 $1 0 UAC_Success ;Are we the real deal or just the wrapper?
InstallDir "$ProgramFiles\${S_NAME}"
    Quit
   
UAC_Err:
    MessageBox mb_iconstop "Unable to elevate, error $0"
    Abort


UAC_ElevationAborted:
!include MUI2.nsh
    # elevation was aborted, run as normal?
!include UAC.nsh
    MessageBox mb_iconstop "This installer requires admin access, aborting!"
    Abort


UAC_Success:
!macro Init thing
    StrCmp 1 $3 +4 ;Admin?
uac_tryagain:
    StrCmp 3 $1 0 UAC_ElevationAborted ;Try again?
!insertmacro UAC_RunElevated
    MessageBox mb_iconstop "This installer requires admin access, try again"
${Switch} $0
    goto UAC_Elevate
${Case} 0
   
${IfThen} $1 = 1 ${|} Quit ${|} ;we are the outer process, the inner process has done its work, we are done
${IfThen} $3 <> 0 ${|} ${Break} ${|} ;we are admin, let the show go on
${If} $1 = 3 ;RunAs completed successfully, but with a non-admin user
MessageBox mb_YesNo|mb_IconExclamation|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, try again" /SD IDNO IDYES uac_tryagain IDNO 0
${EndIf}
;fall-through and die
${Case} 1223
MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, aborting!"
Quit
${Case} 1062
MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Logon service not running, aborting!"
Quit
${Default}
MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Unable to elevate, error $0"
Quit
${EndSwitch}
 
SetShellVarContext all
!macroend
 
Function .onInit
!insertmacro Init "installer"
FunctionEnd
FunctionEnd
</pre>
 
* The NSIS installer launches, and quickly calls its .onInit code (no window is visible by this point yet).  The UAC plugin makes a new process and attempts to elevate it with admin privileges.  If needed, a UAC or Run As dialog is shown to help elevate this second process to admin privileges.  During this point, if you open up Task Manager, you will see two installer processes running.  The user process can be thought of as the outer process, and the admin process the inner process. 
Function un.onInit
* Once elevated, the admin/inner process can display. This is the installer window that users will see. 
!insertmacro Init "uninstaller"
* Now that you have an admin process, you can continue to let your script do its thing. If you ever need to do something at a user level, you do it through the UAC plugin, and the UAC plugin will run whats needed through the hidden user/outer process.  For example, UAC::Exec can execute something with user privileges and not admin privileges.  Or UAC::ExecCodeSegment can execute an entire function with user privileges.
* Before the installer exits, you will need to clean up the plugin.  If you don't, it will leave behind a UAC.dll in the user's %TEMP% folder.  One easy way to clean it up is by supplying the following:
<pre>
Function .OnInstFailed
    UAC::Unload ;Must call unload!
FunctionEnd
FunctionEnd


Function .OnInstSuccess
!insertmacro MUI_PAGE_WELCOME
    UAC::Unload ;Must call unload!
!insertmacro MUI_PAGE_DIRECTORY
FunctionEnd
!insertmacro MUI_PAGE_INSTFILES
</pre>
!define MUI_FINISHPAGE_RUN
Remember that if your installer quits before those events can be fired, you should supply a UAC::Unload before the installer quits.
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
!insertmacro MUI_PAGE_FINISH
 
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES


===Tested environments and notes===
!insertmacro MUI_LANGUAGE "English"


This plugin has been tested under the following environments:


* Windows Vista - UAC On - Administrator
Function PageFinishRun
* Windows Vista - UAC Off - Administrator
; You would run "$InstDir\MyApp.exe" here but this example has no application to execute...
* Windows Vista - UAC On - Standard User - User supplies administrator info into the UAC dialog
!insertmacro UAC_AsUser_ExecShell "" "$WinDir\notepad.exe" "" "" ""
* Windows Vista - UAC On - Standard User - User does not supply administrator info into the UAC dialog
FunctionEnd
* Windows Vista - UAC Off - Standard User - User supplies administrator info into the Run As dialog
* Windows Vista - UAC Off - Standard User - User does not supply administrator info into the Run As dialog
* Windows XP - Administrator
* Windows XP - Limited User - User supplies administrator info into the Run As dialog
* Windows XP - Limited User - User does not supply administrator info into the Run As dialog
* Windows 2000 - Administrator
* Windows 2000 - Standard User - User supplies administrator info into the Run As dialog
* Windows 2000 - Standard User - User does not supply administrator info into the Run As dialog


Windows 98 is untested, but it should work. :)
Section
SetOutPath $InstDir
# TODO: File "MyApp.exe"
WriteUninstaller "$InstDir\Uninstall.exe"
SectionEnd


Notes:  
Section Uninstall
SetOutPath $Temp ; Make sure $InstDir is not the current directory so we can remove it
# TODO: Delete "$InstDir\MyApp.exe"
Delete "$InstDir\Uninstall.exe"
RMDir "$InstDir"
SectionEnd
</highlight-nsis>


# If you need to use the UAC plugin for the uninstaller as well, you will need to initalize the UAC plugin for the uninstaller, such as through un.onInit. Remember to run clean it up with UAC::Unload before your installer exits.  Great places to clean it up are un.OnUnInstFailed and un.OnUnInstSuccess
==Important Notes==
# The outer/user process does not display any output as to what occurred.  If you have the outer/user process create a shortcut, and it fails, the inner/admin process currently visible will not display anything to indicate that a problem occurred.  This is because the outer/user process does not yet communicate back to the inner/admin process.
# If you need to use the UAC plugin for the uninstaller as well, you will need to initalize the UAC plugin for the uninstaller, such as through un.onInit.
# When a standard or limited user supplies administrator information into the Run As dialog, you may experience permissions trouble with any extracted file.  For example, if a Windows 2000 st2andard user supplies administrator info into the Run As dialog, and the NSIS installer extracts an .exe file, then trying to call that .exe through an Exec can fail.  If this is a problem, you will want to use the [[AccessControl_plug-in|AccessControl plug-in]].
# The outer/user process does not display any output as to what occurred.  For example, if you have the outer/user process create a shortcut, and it fails, the inner/admin process currently visible will not display anything to indicate that a problem occurred.  This is because the outer/user process does not yet communicate back to the inner/admin process.
# When a standard or limited user supplies administrator information into the Run As dialog, you may experience permissions trouble with any extracted file.  For example, if a Windows 2000 standard user supplies administrator info into the Run As dialog, and the NSIS installer extracts an .exe file, then trying to call that .exe through an Exec can fail.  If this is a problem, you will want to use the [[AccessControl_plug-in|AccessControl plug-in]].

Latest revision as of 14:32, 21 January 2022

Author: Anders (talk, contrib)


Note:This plug-in is deprecated. It started out as a proof of concept in the early Vista days and should now be considered abandoned.


Plugin Info

  • Version: 0.2.4c (20150526)
  • Type: Runtime plugin
  • Character encoding: Ansi
  • Minimum OS: Win95/NT4 (Elevation on Win2000+)
  • Minimum NSIS Version: 2.45
  • License: zlib
  • Download: UAC.zip (50 KB)


Info

This plug-in attempts to work around UAC installation problems on Win2000+. This plug-in allows your installer to operate with a user level process and an admin level process (administrator broker model). This allows you to accomplish things that would otherwise be very difficult. For example, you can have an elevated installer instance launch another process as the user.

It all started in this thread. It has been field tested with good results. It is still definitely in the beta stage (i.e. use at your own risk).

Basic Example

/*
Basic script for a all users/shared installer.
It runs the installed application as the correct user...
*/
 
!define S_NAME "UAC_Basic example"
Name "${S_NAME}"
OutFile "${S_NAME}.exe"
RequestExecutionLevel user ; << Required, you cannot use admin!
InstallDir "$ProgramFiles\${S_NAME}"
 
!include MUI2.nsh
!include UAC.nsh
 
!macro Init thing
uac_tryagain:
!insertmacro UAC_RunElevated
${Switch} $0
${Case} 0
	${IfThen} $1 = 1 ${|} Quit ${|} ;we are the outer process, the inner process has done its work, we are done
	${IfThen} $3 <> 0 ${|} ${Break} ${|} ;we are admin, let the show go on
	${If} $1 = 3 ;RunAs completed successfully, but with a non-admin user
		MessageBox mb_YesNo|mb_IconExclamation|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, try again" /SD IDNO IDYES uac_tryagain IDNO 0
	${EndIf}
	;fall-through and die
${Case} 1223
	MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, aborting!"
	Quit
${Case} 1062
	MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Logon service not running, aborting!"
	Quit
${Default}
	MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Unable to elevate, error $0"
	Quit
${EndSwitch}
 
SetShellVarContext all
!macroend
 
Function .onInit
!insertmacro Init "installer"
FunctionEnd
 
Function un.onInit
!insertmacro Init "uninstaller"
FunctionEnd
 
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
!insertmacro MUI_PAGE_FINISH
 
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
 
!insertmacro MUI_LANGUAGE "English"
 
 
Function PageFinishRun
; You would run "$InstDir\MyApp.exe" here but this example has no application to execute...
!insertmacro UAC_AsUser_ExecShell "" "$WinDir\notepad.exe" "" "" ""
FunctionEnd
 
Section
SetOutPath $InstDir
# TODO: File "MyApp.exe"
WriteUninstaller "$InstDir\Uninstall.exe"
SectionEnd
 
Section Uninstall
SetOutPath $Temp ; Make sure $InstDir is not the current directory so we can remove it
# TODO: Delete "$InstDir\MyApp.exe"
Delete "$InstDir\Uninstall.exe"
RMDir "$InstDir"
SectionEnd

Important Notes

  1. If you need to use the UAC plugin for the uninstaller as well, you will need to initalize the UAC plugin for the uninstaller, such as through un.onInit.
  2. The outer/user process does not display any output as to what occurred. For example, if you have the outer/user process create a shortcut, and it fails, the inner/admin process currently visible will not display anything to indicate that a problem occurred. This is because the outer/user process does not yet communicate back to the inner/admin process.
  3. When a standard or limited user supplies administrator information into the Run As dialog, you may experience permissions trouble with any extracted file. For example, if a Windows 2000 standard user supplies administrator info into the Run As dialog, and the NSIS installer extracts an .exe file, then trying to call that .exe through an Exec can fail. If this is a problem, you will want to use the AccessControl plug-in.