applied patch #1687456 - [UserInfo plugin] Fix for #1684777, GetAccountType and Vista

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@5033 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
kichik 2007-04-03 10:02:51 +00:00
parent 78f805da52
commit 0cb1253452
2 changed files with 133 additions and 94 deletions

View file

@ -1,5 +1,7 @@
#include <windows.h> #include <windows.h>
#include "../ExDLL/exdll.h" #include "../ExDLL/exdll.h"
typedef BOOL (WINAPI*CHECKTOKENMEMBERSHIP)(HANDLE TokenHandle,PSID SidToCheck,PBOOL IsMember);
CHECKTOKENMEMBERSHIP _CheckTokenMembership=NULL;
void __declspec(dllexport) GetName(HWND hwndParent, int string_size, void __declspec(dllexport) GetName(HWND hwndParent, int string_size,
char *variables, stack_t **stacktop) char *variables, stack_t **stacktop)
@ -17,102 +19,127 @@ void __declspec(dllexport) GetName(HWND hwndParent, int string_size,
} }
} }
void __declspec(dllexport) GetAccountType(HWND hwndParent, int string_size, char* GetAccountTypeHelper(BOOL CheckTokenForGroupDeny)
char *variables, stack_t **stacktop)
{ {
EXDLL_INIT(); char *group;
HANDLE hToken = NULL;
{
HANDLE hThread;
TOKEN_GROUPS *ptg = NULL;
DWORD cbTokenGroups;
DWORD i, j;
SID_IDENTIFIER_AUTHORITY SystemSidAuthority = {SECURITY_NT_AUTHORITY};
char *group = "";
if (GetVersion() & 0x80000000) // Not NT
{
group = "Admin";
}
// First we must open a handle to the access token for this thread.
else if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hThread) ||
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hThread))
{
// Then we must query the size of the group information associated with
// the token. Note that we expect a FALSE result from GetTokenInformation
// because we've given it a NULL buffer. On exit cbTokenGroups will tell
// the size of the group information.
if (!GetTokenInformation (hThread, TokenGroups, NULL, 0, &cbTokenGroups) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
// Now we allocate a buffer for the group information.
// Since _alloca allocates on the stack, we don't have
// to explicitly deallocate it. That happens automatically
// when we exit this function.
if ((ptg = GlobalAlloc(GPTR, cbTokenGroups)))
{
// Now we ask for the group information again.
// This may fail if an administrator has added this account
// to an additional group between our first call to
// GetTokenInformation and this one.
if (GetTokenInformation(hThread, TokenGroups, ptg, cbTokenGroups, &cbTokenGroups))
{
struct group struct group
{ {
DWORD auth_id; DWORD auth_id;
char *name; char *name;
} groups[] = { };
struct group groups[] =
{
{DOMAIN_ALIAS_RID_USERS, "User"}, {DOMAIN_ALIAS_RID_USERS, "User"},
// every user belongs to the users group, hence users comes before guests // every user belongs to the users group, hence users come before guests
{DOMAIN_ALIAS_RID_GUESTS, "Guest"}, {DOMAIN_ALIAS_RID_GUESTS, "Guest"},
{DOMAIN_ALIAS_RID_POWER_USERS, "Power"}, {DOMAIN_ALIAS_RID_POWER_USERS, "Power"},
{DOMAIN_ALIAS_RID_ADMINS, "Admin"} {DOMAIN_ALIAS_RID_ADMINS, "Admin"}
}; };
// Finally we'll iterate through the list of groups for this access if (GetVersion() & 0x80000000) // Not NT
// token looking for a match against the SID we created above. {
return "Admin";
}
// First we must open a handle to the access token for this thread.
if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken) ||
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
SID_IDENTIFIER_AUTHORITY SystemSidAuthority = {SECURITY_NT_AUTHORITY};
TOKEN_GROUPS *ptg = NULL;
BOOL ValidTokenGroups = FALSE;
DWORD cbTokenGroups;
DWORD i, j;
if (CheckTokenForGroupDeny)
// GetUserName is in advapi32.dll so we can avoid Load/Freelibrary
_CheckTokenMembership=
(CHECKTOKENMEMBERSHIP) GetProcAddress(
GetModuleHandle("ADVAPI32"), "CheckTokenMembership");
// Use "old school" membership check?
if (!CheckTokenForGroupDeny || _CheckTokenMembership == NULL)
{
// We must query the size of the group information associated with
// the token. Note that we expect a FALSE result from GetTokenInformation
// because we've given it a NULL buffer. On exit cbTokenGroups will tell
// the size of the group information.
if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &cbTokenGroups) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
// Allocate buffer and ask for the group information again.
// This may fail if an administrator has added this account
// to an additional group between our first call to
// GetTokenInformation and this one.
if ((ptg = GlobalAlloc(GPTR, cbTokenGroups)) &&
GetTokenInformation(hToken, TokenGroups, ptg, cbTokenGroups, &cbTokenGroups))
{
ValidTokenGroups=TRUE;
}
}
}
if (ValidTokenGroups || (CheckTokenForGroupDeny && _CheckTokenMembership))
{
PSID psid;
for (i = 0; i < sizeof(groups)/sizeof(struct group); i++) for (i = 0; i < sizeof(groups)/sizeof(struct group); i++)
{ {
PSID psid = 0; // Create a SID for the local group and then check if it exists in our token
AllocateAndInitializeSid( if (AllocateAndInitializeSid(
&SystemSidAuthority, &SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
2, groups[i].auth_id, 0, 0, 0, 0, 0, 0,&psid))
SECURITY_BUILTIN_DOMAIN_RID, {
groups[i].auth_id, BOOL IsMember = FALSE;
0, 0, 0, 0, 0, 0, if (CheckTokenForGroupDeny && _CheckTokenMembership)
&psid {
); _CheckTokenMembership(0, psid, &IsMember);
if (psid == 0) continue; }
else if (ValidTokenGroups)
{
for (j = 0; j < ptg->GroupCount; j++) for (j = 0; j < ptg->GroupCount; j++)
{
if (EqualSid(ptg->Groups[j].Sid, psid)) if (EqualSid(ptg->Groups[j].Sid, psid))
group = groups[i].name; {
IsMember = TRUE;
}
}
}
if (IsMember) group=groups[i].name;
FreeSid(psid); FreeSid(psid);
} }
} }
}
if (ptg)
GlobalFree(ptg); GlobalFree(ptg);
} CloseHandle(hToken);
return group;
} }
CloseHandle(hThread); return "";
} }
pushstring(group); void __declspec(dllexport) GetAccountType(HWND hwndParent, int string_size,
char *variables, stack_t **stacktop)
{
EXDLL_INIT();
pushstring(GetAccountTypeHelper(TRUE));
} }
void __declspec(dllexport) GetOriginalAccountType(HWND hwndParent, int string_size,
char *variables, stack_t **stacktop)
{
EXDLL_INIT();
pushstring(GetAccountTypeHelper(FALSE));
} }
BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{ {
return TRUE; return TRUE;
} }

View file

@ -1,6 +1,8 @@
Name "UserInfo.dll test" Name "UserInfo.dll test"
OutFile UserInfo.exe OutFile UserInfo.exe
!define REALMSG "$\nOriginal non-restricted account type: $2"
Section Section
ClearErrors ClearErrors
UserInfo::GetName UserInfo::GetName
@ -8,17 +10,26 @@ Section
Pop $0 Pop $0
UserInfo::GetAccountType UserInfo::GetAccountType
Pop $1 Pop $1
# GetOriginalAccountType will check the tokens of the original user of the
# current thread/process. If the user tokens were elevated or limited for
# this process, GetOriginalAccountType will return the non-restricted
# account type.
# On Vista with UAC, for example, this is not the same value when running
# with `RequestExecutionLevel user`. GetOriginalAccountType will return
# "admin" while GetAccountType will return "user".
UserInfo::GetOriginalAccountType
Pop $2
StrCmp $1 "Admin" 0 +3 StrCmp $1 "Admin" 0 +3
MessageBox MB_OK 'User "$0" is in the Administrators group' MessageBox MB_OK 'User "$0" is in the Administrators group${REALMSG}'
Goto done Goto done
StrCmp $1 "Power" 0 +3 StrCmp $1 "Power" 0 +3
MessageBox MB_OK 'User "$0" is in the Power Users group' MessageBox MB_OK 'User "$0" is in the Power Users group${REALMSG}'
Goto done Goto done
StrCmp $1 "User" 0 +3 StrCmp $1 "User" 0 +3
MessageBox MB_OK 'User "$0" is just a regular user' MessageBox MB_OK 'User "$0" is just a regular user${REALMSG}'
Goto done Goto done
StrCmp $1 "Guest" 0 +3 StrCmp $1 "Guest" 0 +3
MessageBox MB_OK 'User "$0" is a guest' MessageBox MB_OK 'User "$0" is a guest${REALMSG}'
Goto done Goto done
MessageBox MB_OK "Unknown error" MessageBox MB_OK "Unknown error"
Goto done Goto done
@ -30,3 +41,4 @@ Section
done: done:
SectionEnd SectionEnd