OK, Thanks to Loaden found out that my original code to determine whether an user is in Administrators group is totally bullshit.
And after googling for a while, I found something and test it, simply works. I will just paste the code here. Thanks to the author and google and God.
http://www.mihai-nita.net/article.php?artID=20070413a
// IsAdminAPI.cpp : Tests if user is Administrator using plain Win32 API
// Copyright (c) April 2007, Mihai Nita
//
#include <wtypes.h>
#include <Lm.h>
// for ASSERT
#include <crtdbg.h>
#include "IsAdminAPI.h"
bool IsAdminAPI( WCHAR const *szUserName )
{
_ASSERT(szUserName);
bool bAdmin = FALSE;
LOCALGROUP_USERS_INFO_0* localGroups;
DWORD entriesread, totalentries;
NET_API_STATUS nts = NetUserGetLocalGroups( NULL, szUserName, 0, 0, (unsigned char**)&localGroups, MAX_PREFERRED_LENGTH, &entriesread, &totalentries);
if( nts != NERR_Success ) {
NetApiBufferFree(localGroups);
return FALSE;
}
// Retrieve the Administrators group well-known SID
// For some reason CreateWellKnownSid generates error C3861 on Developer Studio .NET:
// error C3861: 'CreateWellKnownSid': identifier not found, even with argument-dependent lookup
BYTE SidAuth[] = SECURITY_NT_AUTHORITY;
PSID pAdminSid;
AllocateAndInitializeSid( (PSID_IDENTIFIER_AUTHORITY)SidAuth,
2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
NULL, NULL, NULL, NULL, NULL, NULL, &pAdminSid );
// Will use this to retrieve the SID of the group
BYTE buffSid[SECURITY_MAX_SID_SIZE];
wchar_t buffDomain[DNLEN+1];
DWORD dwSidSize;
DWORD dwDomainSize;
SID_NAME_USE m_sidnameuse;
for( DWORD i = 0; i < entriesread; ++i ) {
dwSidSize = sizeof(buffSid);
dwDomainSize = DNLEN;
// Although in general is a bad idea to call directly the W or A versions of API
// we do it here to avoid converting the localGroups[i].lgrui0_name back to ANSI
// This kind of security API is only present on NT/2000/XP family only, so
// the W version is present and safe to use
if( LookupAccountNameW( NULL, localGroups[i].lgrui0_name, buffSid, &dwSidSize, (LPWSTR)buffDomain, &dwDomainSize, &m_sidnameuse) ) // no sid for the actual group
if( EqualSid( buffSid, pAdminSid ) ) {
bAdmin = TRUE;
break;
}
}
FreeSid( pAdminSid );
NetApiBufferFree(localGroups);
return bAdmin;
}
注意有时我们只需要判断当前process是否以管理员权限运行。貌似可以通过调用GetTokenInformation 和AllocateAndInitializeSid 来判断,
google "Searching for a SID in an Access Token in C++" site:msdn.microsoft.com可找到一段代码, 请自行研究自行测试。
#define MAX_NAME 256
BOOL SearchTokenGroupsForSID (VOID)
{
DWORD i, dwSize = 0, dwResult = 0;
HANDLE hToken;
PTOKEN_GROUPS pGroupInfo;
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
BYTE sidBuffer[100];
PSID pSID = (PSID)&sidBuffer;
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
// Open a handle to the access token for the calling process.
if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken )) {
printf( "OpenProcessToken Error %u\n", GetLastError() );
return FALSE;
}
// Call GetTokenInformation to get the buffer size.
if(!GetTokenInformation(hToken, TokenGroups, NULL, dwSize, &dwSize)) {
dwResult = GetLastError();
if( dwResult != ERROR_INSUFFICIENT_BUFFER ) {
printf( "GetTokenInformation Error %u\n", dwResult );
return FALSE;
}
}
// Allocate the buffer.
pGroupInfo = (PTOKEN_GROUPS) GlobalAlloc( GPTR, dwSize );
// Call GetTokenInformation again to get the group information.
if(! GetTokenInformation(hToken, TokenGroups, pGroupInfo,
dwSize, &dwSize ) ) {
printf( "GetTokenInformation Error %u\n", GetLastError() );
return FALSE;
}
// Create a SID for the BUILTIN\Administrators group.
if(! AllocateAndInitializeSid( &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pSID) ) {
printf( "AllocateAndInitializeSid Error %u\n", GetLastError() );
return FALSE;
}
// Loop through the group SIDs looking for the administrator SID.
for(i=0; i<pGroupInfo->GroupCount; i++) {
if ( EqualSid(pSID, pGroupInfo->Groups[i].Sid) ) {
// Lookup the account name and print it.
dwSize = MAX_NAME;
if( !LookupAccountSid( NULL, pGroupInfo->Groups[i].Sid,
lpName, &dwSize, lpDomain,
&dwSize, &SidType ) ) {
dwResult = GetLastError();
if( dwResult == ERROR_NONE_MAPPED )
strcpy_s (lpName, dwSize, "NONE_MAPPED" );
else {
printf("LookupAccountSid Error %u\n", GetLastError());
return FALSE;
}
}
printf( "Current user is a member of the %s\\%s group\n",
lpDomain, lpName );
// Find out whether the SID is enabled in the token.
if (pGroupInfo->Groups[i].Attributes & SE_GROUP_ENABLED)
printf("The group SID is enabled.\n");
else if (pGroupInfo->Groups[i].Attributes &
SE_GROUP_USE_FOR_DENY_ONLY)
printf("The group SID is a deny-only SID.\n");
else
printf("The group SID is not enabled.\n");
}
}
if (pSID)
FreeSid(pSID);
if ( pGroupInfo )
GlobalFree( pGroupInfo );
return TRUE;
}
向曾被我误导的同志表示真挚的道歉和沉痛的悼念。
NSIS下判断当前用户是否管理员:
http://nsis.sourceforge.net/Check_if_the_current_user_is_an_Administrator
!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