Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request UAC elevation for installer #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

sredna
Copy link

@sredna sredna commented Jun 6, 2023

You are writing to ProgramFiles and HKLM so you should be requesting UAC elevation.

@malxau
Copy link
Owner

malxau commented Jun 6, 2023

The current behavior is imperfect but intentional. WinCvt doesn't need to be installed as Administrator; it needs write access to wherever it's installed.

The real issue though - which judging by StartRegedit you've already encountered - is that it's relatively easy for a user to ask a program to run as Admin, while infuriatingly difficult to ask a program to run as a regular user. So if the installer prompts for elevation, in a practical sense, regular users couldn't run it.

What would be nice would be to use different install directory defaults depending on whether it's elevated or not, so an elevated process defaults to Program Files and a non-elevated one defaults to AppData. I've seen NSIS installers do this before - do you know the best way to do something like that? Right now I'm looking at https://nsis.sourceforge.io/Check_if_the_current_user_is_an_Administrator , which I'd believe works, but looks rather gross.

@sredna
Copy link
Author

sredna commented Jun 6, 2023

The current behavior is imperfect but intentional. WinCvt doesn't need to be installed as Administrator; it needs write access to wherever it's installed.
...
So if the installer prompts for elevation, in a practical sense, regular users couldn't run it.

If we ignore the power users group (deprecated in Vista), how many non-admins can write to HKLM?

RequestExecutionLevel Highest will only UAC prompt administrators and not regular users but that is still wrong as long as you hardcode HKLM (IMHO) but in your case might just do the trick. But I do see your point of view, it does not look like any of your registry writes are critical, the user will just lose "open with" and uninstall info.

What would be nice would be to use different install directory defaults depending on whether it's elevated or not, so an elevated process defaults to Program Files and a non-elevated one defaults to AppData. I've seen NSIS installers do this before - do you know the best way to do something like that?

Yes but it is tricky to get right. Something like:

  • Use RequestExecutionLevel Highest
  • Don't use InstallDir so you can detect the /D= switch.
  • In .onInit you initialize two custom variables and set stuff up
StrCpy $LMDefDir "$ProgramFiles\$(^Name)"
GetKnownFolderPath $CUDefDir {5CD7AEE2-2219-4A67-B85D-6C9CE15660CB} ; FOLDERID_UserProgramFiles, this folder only exists on Win7+
StrCmp $CUDefDir "" 0 +2 
  StrCpy $CUDefDir "$LocalAppData\Programs" ; Fallback directory
StrCpy $CUDefDir "$CUDefDir\$(^Name)"

${If} IsAdminCheckHere... (and maybe try to detect existing install type and location (if any))
  SetShellVarContext All
  StrCmp $InstDir "" 0 +2
    StrCpy $InstDir $LMDefDir
${Else}
  SetShellVarContext Current
  StrCmp $InstDir "" 0 +2
    StrCpy $InstDir $CUDefDir
${EndIf}
  • All registry writes need to use ShCtx, not HKCU nor HKLM!
  • The Uninstaller needs a way to detect the install type so it can call SetShellVarContext in un.onInit. Write the type (IfShellVarContextAll) to a .ini or in the OEM part of the PE in the uninstaller itself (FileWriteByte at IMAGE_DOS_HEADER::e_res2).
  • A custom page with two radio buttons (Current and All users) that sets $InstDir to something before reaching the directory page.

MultiUser.nsh is supposed to help you with most of this. I did not design it but I have tried to wrestle it into working as described above.

...but looks rather gross.

Indeed.

UserInfo::GetAccountType
Pop $0 ; $0 is now "admin" or something else (user, guest, etc.)

or if you want to do it without plug-ins for some reason, write a GUID string to HKLM and delete it again. IfErrors is true if not "admin".

A completely different option would be to decide that your installer is only per-user. Keep RequestExecutionLevel User and change InstallDir, HKLM -> HKCU and HKCR -> HKCU\Software\Classes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants