我想从一个非特权应用程序运行一个特权应用程序。但是我想在启动应用程序之前检查用户是否是管理员。
Win32 提供IsUserAnAdmin()
和IsUserAdmin()
但如果从非特权进程调用,这两者都将返回0
。这是因为它真正要做的是询问进程是否具有管理访问权限,而不是询问用户是否是 \Administrators 组的成员。
是否可以确定用户是否属于非特权进程的管理员组?
已经有几个类似的问题,但这不是重复的。具体来说,我想知道用户是否是组的一部分,而不是进程是否继承了管理权限;以及是否可以使用 Win32(不是 .NET)完成。
如果您有用户令牌的句柄(来自OpenProcessToken
等),则可以执行忽略"仅拒绝"组的经典管理员检查: 调用GetTokenInformation(..., TokenGroups, ...)
并查找管理员组 SID。
如果您只有一个用户名/SID,则可以使用 NetUserGetLocalGroups 或 NetLocalGroupGetMembers
。
首先需要检查您的令牌TOKEN_ELEVATION_TYPE
。
如果您获得TokenElevationTypeDefault
或TokenElevationTypeFull
- 您无法提升和最大值,您可以在令牌中已有的此用户帐户下拥有的最大值。 对于查询是令牌是管理员还是您有一些权限 - 需要按原样查询您当前的令牌。
如果得到TokenElevationTypeLimited
- 需要通过TokenLinkedToken
查询链接令牌,并检查此链接令牌而不是当前令牌 - 因为在提升特权应用程序后将使用此令牌。
例如:
ULONG IsTokenAdmin(HANDLE hToken, PBOOL pbIsAdmin)
{
ULONG cbSid = MAX_SID_SIZE;
PSID pSid = alloca(cbSid);
return CreateWellKnownSid(::WinBuiltinAdministratorsSid, 0, pSid, &cbSid) &&
CheckTokenMembership(hToken, pSid, pbIsAdmin) ? NOERROR : GetLastError();
}
ULONG IsUserAnAdminEx(PBOOL pbIsAdmin, PBOOL pbNeedElevate)
{
ULONG dwError = NOERROR;
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &hToken))
{
ULONG cb;
union {
TOKEN_ELEVATION_TYPE tet;
TOKEN_LINKED_TOKEN tlt;
};
if (GetTokenInformation(hToken, ::TokenElevationType, &tet, sizeof(tet), &cb))
{
switch (tet)
{
case TokenElevationTypeLimited:
*pbNeedElevate = TRUE;
if (GetTokenInformation(hToken, ::TokenLinkedToken, &tlt, sizeof(tlt), &cb))
{
dwError = IsTokenAdmin(tlt.LinkedToken, pbIsAdmin);
CloseHandle(tlt.LinkedToken);
}
else
{
dwError = GetLastError();
}
break;
case TokenElevationTypeFull:
case TokenElevationTypeDefault:
*pbNeedElevate = FALSE;
// only because CheckTokenMembership want an impersonation token.
// really most query can be and must be done direct with this token
if (DuplicateToken(hToken, ::SecurityIdentification, &tlt.LinkedToken))
{
dwError = IsTokenAdmin(tlt.LinkedToken, pbIsAdmin);
CloseHandle(tlt.LinkedToken);
}
else
{
GetLastError();
}
break;
default:
dwError = ERROR_GEN_FAILURE;
}
}
else
{
dwError = GetLastError();
}
CloseHandle(hToken);
}
return dwError;
}