Archive: IsUserAdmin?


IsUserAdmin?
I have seen similar functionality in a plugin and I wanted to achieve the same using the system plugin, thus trimming down the size of my installer a bit. It turned out to be quite easy :)

The following code uses the CheckTokenMembership function of advapi32.dll, works in NT/2k/XP etc and it returns 1 if the user belongs to the administrator's group, 0 if not and -1 if an error occurs:

!macro IsUserAdmin RESULT
!define Index "Line${__LINE__}"
StrCpy ${RESULT} 0
System::Call '*(&i1 0,&i4 0,&i1 5)i.r0'
System::Call 'advapi32::AllocateAndInitializeSid(i r0,i 2,i 32,i 544,i 0,i 0,i 0,i 0,i 0,i 0,*i .R0)i.r5'
System::Free $0
System::Call 'advapi32::CheckTokenMembership(i n,i R0,*i .R1)i.r5'
StrCmp $5 0 ${Index}_Error
StrCpy ${RESULT} $R1
Goto ${Index}_End
${Index}_Error:
StrCpy ${RESULT} -1
${Index}_End:
System::Call 'advapi32::FreeSid(i R0)i.r5'
!undef Index
!macroend

Usage:
...
!insertmacro IsUserAdmin $1
; $1 = 1 true
; $1 = 0 false
; $1 = -1 there was an error
...

I hope this is useful for others as well :)
CF

CheckTokenMembership is a nice little useful function, but sadly it's not available on NT. You should use a different method, if you intend to support NT.


Good point kichik, thanks for pointing that out :o

Using the IsAdministrator functionality from the XtInfoPlugin plugin I wrote the following code which uses the system plugin:

!define TOKEN_READ   0x00020008
!define TokenGroups 2

!macro IsUserAdmin RESULT
!define Index "Line${__LINE__}"
StrCpy ${RESULT} 0

# Construct the SID for the Admin group - Should get S-1-5-32-544 for administrators (place it in $R4)
System::Call "*(&i1 0,&i4 0,&i1 5)i.r0"
System::Call "advapi32::AllocateAndInitializeSid(i r0,i 2,i 32,i 544,i 0,i 0,i 0,i 0,i 0,i 0,*i .R4)i.r5"
System::Free $0

# Get a psuedo-handle of the current process and place it on R0
System::Call 'kernel32::GetCurrentProcess()i.R0'

# Open the Token from the psuedo process and place the handle on R1
System::Call 'advapi32::OpenProcessToken(i R0,i ${TOKEN_READ},*i .R1)i.R9'

# Get info from the token and place it in $R2 (the size goes to $R3)
System::Call 'advapi32::GetTokenInformation(i R1,i ${TokenGroups},*i .R2,i 0,*i .R3)i.R9'
System::Alloc $R3
Pop $R2
System::Call 'advapi32::GetTokenInformation(i R1,i ${TokenGroups},i R2,i $R3,*i .R3)i.R9'

# Check how many TOKEN_GROUPS elements are in $R2 (place the number in $R5)
System::Call '*$R2(i.R5,i.R6)'

# Compare the SID structures
StrCpy $1 0

${Index}_Start:
StrCmp $1 $R5 ${Index}_Stop
System::Call 'advapi32::EqualSid(i R4,i R6)i.R9'
StrCmp $R9 "" ${Index}_Increment
StrCmp $R9 0 +1 +3
StrCpy ${RESULT} 0
Goto ${Index}_Increment
StrCpy ${RESULT} 1
System::Call 'advapi32::FreeSid(i R6)i.R8'
Goto ${Index}_Stop
${Index}_Increment:
System::Call 'advapi32::GetLengthSid(i R6)i.R9'
System::Call 'advapi32::FreeSid(i R6)i.R8'
IntOp $R6 $R6 + $R9
IntOp $1 $1 + 1
Goto ${Index}_Start

${Index}_Stop:
# Close the token handle
System::Call 'kernel32::CloseHandle(i R1)i.R9'

# cleanup
System::Call 'advapi32::FreeSid(i R4)i.r5'
System::Free $R2
System::Free 0

!undef Index
!macroend

It can be used as the previous macro:
...
!insertmacro IsUserAdmin $1
; $1 = 1 true
; $1 = 0 false
...

The above code should be compatible with NT as well.
I didn't add any error checking though for this one ...
CF

Hi CancerFace,

I tried use this macro, but I have as result blank value.
Would you be able to check this code and give your advise.
Thanks.

Macro file is:


!macro IsUserAdmin RESULT
!define Index "Line${__LINE__}"
StrCpy ${RESULT} 0
System::Call '*(&i1 0,&i4 0,&i1 5)i.r0'
System::Call 'advapi32::AllocateAndInitializeSid(i r0,i 2,i 32,i 544,i 0,i 0,i 0,i 0,i 0, \
i 0,*i .R0)i.r5'
System::Free $0
System::Call 'advapi32::CheckTokenMembership(i n,i R0,*i .R1)i.r5'
StrCmp $5 0 ${Index}_Error
StrCpy ${RESULT} $R1
Goto ${Index}_End
${Index}_Error:
StrCpy ${RESULT} -1
${Index}_End:
System::Call 'advapi32::FreeSid(i R0)i.r5'
!undef Index
!macroend


Script is:

var tmp1
!include folderpath\include\IsCurrentUserAdmin.nsh

!insertmacro WriteLog "Check current user permissions" "$log_name.log"
StrCpy $tmp1 "-2"
ClearErrors
DetailPrint "current user permissions IS: $tmp1"
Sleep 2000
!insertmacro WriteLog "current user permissions IS: $tmp1" "$log_name.log"
Sleep 2000

!insertmacro IsUserAdmin $tmp1
Pop $tmp1
; ${If} $tmp1 = "1"
; Goto CurrentUserIsAdmin
; ${EndIf}
!insertmacro WriteLog "current user permissions IS: $tmp1" "$log_name.log"
DetailPrint "current user permissions IS: $tmp1"
Sleep 2000


Result in log file is:

23/10/2006 (Monday) 11:53:31
Check current user permissions
23/10/2006 (Monday) 11:53:33
current user permissions IS: -2
23/10/2006 (Monday) 11:53:35
current user permissions IS:

No need to use Pop $tmp1 after calling the macro...
Could it be that your stack has -2 on the top and you are popping it into your variable?
CF


PS Looking at this again, you define $tmp1 as -2, then you pass it to the macro (which should set $tmp1 to 0, 1 or -1, and then you Pop the top of the stack to $tmp1 (not sure why you do that) ...

Where are you defining $tmp1? Is your var $tmp1 statement inside a function/section? If yes then you should either use var /GLOBAL or define it beforeyour sections...

Also I hope that you are running the above macro in Win2k/XP/2k3 and [u]not[/i] 9x/NT (check the rest of the thread)


I also forgot to mention that I have added a wiki page for these macros ...
CF


Thanks a lot!

I remarked Pop $tmp1 after !insertmacro and I had correct value for $tmp1.

Would you be able to help check my logic?


!insertmacro IsUserAdmin $tmp1
; Pop $tmp1
; ${If} $tmp1 = "1"
; Goto CurrentUserIsAdmin
; ${EndIf}
!insertmacro WriteLog "current user permissions IS: $tmp1" "$log_name.log"
DetailPrint "current user permissions IS: $tmp1"

!if $tmp1 < 0
!insertmacro WriteLog "Can not check current user permissions" "$log_name.log"
DetailPrint "Can not check current user permissions."
Sleep 1000
!else
!if $tmp1 > 0
!insertmacro WriteLog "Current user has Administrator permissions" "$log_name.log"
DetailPrint "Current user has Administrator permissions."
Sleep 1000
!else
!insertmacro WriteLog "Current user has NOT Administrator permissions" "$log_name.log"
DetailPrint "Current user has NOT Administrator permissions."
Sleep 1000
!endif
!endif

!insertmacro WriteLog "current user permissions IS: $tmp1" "$log_name.log"
Sleep 1000
Quit


Log file is:

24/10/2006 (Tuesday) 10:20:51
current user permissions IS: 1
24/10/2006 (Tuesday) 10:20:51
Current user has NOT Administrator permissions
24/10/2006 (Tuesday) 10:20:53
current user permissions IS: 1


P.S. I found yours macro in NSIS wiki - THANKS.

Sorry for question, I found logic solution:


var tmp1
!include LogicLib.nsh

!insertmacro IsUserAdmin $tmp1

${If} $tmp1 == 1
!insertmacro WriteLog "Current user has Administrator permissions" "$log_name.log"
SetDetailsPrint textonly
DetailPrint "Current user has Administrator permissions."
Sleep 1000
${Else}
${If} $tmp1 == 0
!insertmacro WriteLog "Current user has NOT Administrator permissions" "$log_name.log"
SetDetailsPrint textonly
DetailPrint "Current user has NOT Administrator permissions."
Sleep 1000
${Else}
!insertmacro WriteLog "Can not check current user permissions" "$log_name.log"
Goto End_Failed
${EndIf}
${EndIf}

Thanks a lot