- NSIS Discussion
- IsUserAdmin?
Archive: IsUserAdmin?
CancerFace
23rd August 2006 09:51 UTC
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
kichik
25th August 2006 12:44 UTC
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.
CancerFace
26th August 2006 12:10 UTC
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
vadzen
23rd October 2006 12:33 UTC
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:
CancerFace
23rd October 2006 12:40 UTC
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)
CancerFace
23rd October 2006 15:12 UTC
I also forgot to mention that I have added a wiki page for these macros ...
CF
vadzen
24th October 2006 10:33 UTC
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.
vadzen
24th October 2006 19:13 UTC
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