As Hans Passant points out in his answer, the real underlying question - why in this scenario you would want to check the manifest - is:
How to check whether the current user can run the process with elevated privileges?
As suggested in the question, the following would work:
var myPrincipal = new WindowsPrincipal( WindowsIdentity.GetCurrent() );
if ( !myPrincipal.IsInRole( WindowsBuiltInRole.Administrator ) &&
IsUserInAdminGroup() )
{
throw new NotSupportedException( "Some useful comments ..." );
}
The main question is thus, how do you write IsUserInAdminGroup()
? The code listed in the UAC self-elevation sample albeit useful, doesn't explain what is going on, and why it is needed.
Hans Passant replied in a comment "Windows emulates a non-elevated process too well, no way to tell from .NET that the user account is in fact an admin account. Falling back to interrogating the token with pinvoke is the workaround used in the linked code.".
In short, you'll need to rely on P/Invoke in order to implement IsUserInAdminGroup()
, of which the code can be found in the UAC sample.
More interesting perhaps, is why?
In order to find out I refactored the sample code and incorporated the function into my library. The result in my opinion is a bit more clear. Below you can find the outline, the comments are probably more relevant than the code since it depends on other classes etc ...
Starting from Windows Vista, you have different token types as expressed by TOKEN_ELEVATION_TYPE. Although you can access WindowsIdentity.Token
through .NET, this isn't the token we need to check whether someone is administrator. This is a limited token. It has a linked elevated token attached to it, but this isn't exposed in .NET.
Pretty much all the (semi-pseudo) code below does is look up whether there is such an elevated token attached to the original token, and use that to check IsInRole()
instead.
// 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 );