我需要找到一种方法来保证使用我的库的人在应用程序清单中将requestedExecutionLevel
设置为最小highestAvailable
,如下所示:
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
</requestedPrivileges>
当他们没有正确设置清单时,我想抛出异常,以便开发人员知道这个需求,而无需阅读文档。
主要问题:是否可以访问此信息,如果是这样的话?
我已经考虑过检查此设置的结果,而不是检查此设置。设置为highestAvailable
时,我希望管理员组的任何用户部分都以管理员身份运行。
这可以使用:
答案 0 :(得分:7)
您的方法存在缺陷,使用您的库的开发人员会非常不喜欢它。问题是清单不是使进程升级的唯一方法。事实上,在调试代码时,几乎从未像现在这样,Visual Studio托管过程是您运行的EXE,并且具有活动清单,没有“highestAvailable”。开发人员将提升Visual Studio本身,他开始的程序继承安全令牌并且也会升级。
>这很难得到,如果进程没有提升,那么安全令牌就是普通用户之一。
您需要代码available here。如果IsUserInAdminGroup为true且IsProcessElevated为false,则抛出异常。
答案 1 :(得分:0)
作为Hans Passant points out in his answer,真正的基本问题 - 为什么在这种情况下你想检查清单 - 是:
如何检查当前用户是否可以使用提升的权限运行进程?
正如问题所示,以下内容可行:
var myPrincipal = new WindowsPrincipal( WindowsIdentity.GetCurrent() );
if ( !myPrincipal.IsInRole( WindowsBuiltInRole.Administrator ) &&
IsUserInAdminGroup() )
{
throw new NotSupportedException( "Some useful comments ..." );
}
主要问题是,你如何写IsUserInAdminGroup()
? code listed in the UAC self-elevation sample虽然有用,但不能解释发生了什么,以及为什么需要它。
Hans Passant回复in a comment “Windows模拟了一个非提升的进程,无法告诉.NET用户帐户实际上是一个管理员帐户。回过头来查询令牌pinvoke是链接代码中使用的解决方法。“。
简而言之,您需要依赖P / Invoke 才能实现IsUserInAdminGroup()
,其代码可以找到in the UAC sample。
或许更有趣,是为什么?
为了找出I refactored the sample code and incorporated the function into my library。我认为结果更清楚一些。下面你可以找到大纲,评论可能比代码更相关,因为它取决于其他类等...
从Windows Vista开始,您有TOKEN_ELEVATION_TYPE所表示的不同令牌类型。虽然您可以通过.NET访问WindowsIdentity.Token
,但这不是我们需要检查某人是否为管理员的令牌。这是有限令牌。它附加了一个链接的提升令牌,但这不会在.NET中公开。
下面几乎所有的(半伪)代码都会查找原始令牌是否附加了这样一个提升的令牌,并使用它来检查IsInRole()
。
// Default token's received aren't impersonation tokens,
// we are looking for an impersonation token.
bool isImpersonationToken = false;
// Open the access token of the current process.
SafeTokenHandle processToken;
if ( !AdvApi32.OpenProcessToken( ..., out processToken ) )
{
MarshalHelper.ThrowLastWin32ErrorException();
}
// Starting from Vista linked tokens are supported which need to be checked.
if ( EnvironmentHelper.VistaOrHigher )
{
// Determine token type: limited, elevated, or default.
SafeUnmanagedMemoryHandle elevationTypeHandle = ...;
if ( !AdvApi32.GetTokenInformation( ... elevationTypeHandle ) )
{
MarshalHelper.ThrowLastWin32ErrorException();
}
var tokenType = (AdvApi32.TokenElevationType)Marshal.ReadInt32(
elevationTypeHandle.DangerousGetHandle() );
// If limited, get the linked elevated token for further check.
if ( tokenType == AdvApi32.TokenElevationType.TokenElevationTypeLimited )
{
// Get the linked token.
SafeUnmanagedMemoryHandle linkedTokenHandle = ...;
if ( !AdvApi32.GetTokenInformation( ... linkedTokenHandle ) )
{
MarshalHelper.ThrowLastWin32ErrorException();
}
processToken = new SafeTokenHandle(
Marshal.ReadIntPtr( linkedTokenHandle.DangerousGetHandle() ) );
// Linked tokens are already impersonation tokens.
isImpersonationToken = true;
}
}
// We need an impersonation token in order
// to check whether it contains admin SID.
if ( !isImpersonationToken )
{
SafeTokenHandle impersonatedToken;
if ( !AdvApi32.DuplicateToken( ..., out impersonatedToken ) )
{
MarshalHelper.ThrowLastWin32ErrorException();
}
processToken = impersonatedToken;
}
// Check if the token to be checked contains admin SID.
var identity= new WindowsIdentity( processToken.DangerousGetHandle() );
var principal = new WindowsPrincipal( identity );
return principal.IsInRole( WindowsBuiltInRole.Administrator );