web-dev-qa-db-ja.com

.NET / C#で、プロセスに管理者権限があるかどうかをテストする

プロセスにマシンの管理者権限があるかどうかをテストする標準的な方法はありますか?

長時間実行されるプロセスを開始しますが、プロセスの有効期間のずっと後に、管理者特権を必要とするいくつかのことを試みます。

プロセスが後でそれらの権利を持っているかどうかを事前にテストできるようにしたいと思います。

49
Clinton Pierce

これにより、ユーザーがローカルのAdministratorsグループに属しているかどうかが確認されます(ドメイン管理者のアクセス許可を確認していない場合)

using System.Security.Principal;

public bool IsUserAdministrator()
{
    //bool value to hold our return value
    bool isAdmin;
    WindowsIdentity user = null;
    try
    {
        //get the currently logged in user
        user = WindowsIdentity.GetCurrent();
        WindowsPrincipal principal = new WindowsPrincipal(user);
        isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
    }
    catch (UnauthorizedAccessException ex)
    {
        isAdmin = false;
    }
    catch (Exception ex)
    {
        isAdmin = false;
    }
    finally
    {
        if (user != null)
            user.Dispose();
    }
    return isAdmin;
}
77
Wadih M.

Wadih Mのコードから始めて、UACがオンの場合のケースを処理しようとする追加のP/Invokeコードがあります。

http://www.davidmoore.info/blog/2011/06/20/how-to-check-if-the-current-user-is-an-administrator-even-if-uac-is- on /

まず、GetTokenInformation API呼び出しをサポートするためのコードが必要です。

[DllImport("advapi32.dll", SetLastError = true)]
static extern bool GetTokenInformation(IntPtr tokenHandle, TokenInformationClass tokenInformationClass, IntPtr tokenInformation, int tokenInformationLength, out int returnLength);

/// <summary>
/// Passed to <see cref="GetTokenInformation"/> to specify what
/// information about the token to return.
/// </summary>
enum TokenInformationClass
{
     TokenUser = 1,
     TokenGroups,
     TokenPrivileges,
     TokenOwner,
     TokenPrimaryGroup,
     TokenDefaultDacl,
     TokenSource,
     TokenType,
     TokenImpersonationLevel,
     TokenStatistics,
     TokenRestrictedSids,
     TokenSessionId,
     TokenGroupsAndPrivileges,
     TokenSessionReference,
     TokenSandBoxInert,
     TokenAuditPolicy,
     TokenOrigin,
     TokenElevationType,
     TokenLinkedToken,
     TokenElevation,
     TokenHasRestrictions,
     TokenAccessInformation,
     TokenVirtualizationAllowed,
     TokenVirtualizationEnabled,
     TokenIntegrityLevel,
     TokenUiAccess,
     TokenMandatoryPolicy,
     TokenLogonSid,
     MaxTokenInfoClass
}

/// <summary>
/// The elevation type for a user token.
/// </summary>
enum TokenElevationType
{
    TokenElevationTypeDefault = 1,
    TokenElevationTypeFull,
    TokenElevationTypeLimited
}

次に、ユーザーが管理者であるかどうかを検出する実際のコード(そうである場合はtrue、そうでない場合はfalseを返します)。

var identity = WindowsIdentity.GetCurrent();
if (identity == null) throw new InvalidOperationException("Couldn't get the current user identity");
var principal = new WindowsPrincipal(identity);

// Check if this user has the Administrator role. If they do, return immediately.
// If UAC is on, and the process is not elevated, then this will actually return false.
if (principal.IsInRole(WindowsBuiltInRole.Administrator)) return true;

// If we're not running in Vista onwards, we don't have to worry about checking for UAC.
if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 6)
{
     // Operating system does not support UAC; skipping elevation check.
     return false;
}

int tokenInfLength = Marshal.SizeOf(typeof(int));
IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInfLength);

try
{
    var token = identity.Token;
    var result = GetTokenInformation(token, TokenInformationClass.TokenElevationType, tokenInformation, tokenInfLength, out tokenInfLength);

    if (!result)
    {
        var exception = Marshal.GetExceptionForHR( Marshal.GetHRForLastWin32Error() );
        throw new InvalidOperationException("Couldn't get token information", exception);
    }

    var elevationType = (TokenElevationType)Marshal.ReadInt32(tokenInformation);

    switch (elevationType)
    {
        case TokenElevationType.TokenElevationTypeDefault:
            // TokenElevationTypeDefault - User is not using a split token, so they cannot elevate.
            return false;
        case TokenElevationType.TokenElevationTypeFull:
            // TokenElevationTypeFull - User has a split token, and the process is running elevated. Assuming they're an administrator.
            return true;
        case TokenElevationType.TokenElevationTypeLimited:
            // TokenElevationTypeLimited - User has a split token, but the process is not running elevated. Assuming they're an administrator.
            return true;
        default:
            // Unknown token elevation type.
            return false;
     }
}
finally
{    
    if (tokenInformation != IntPtr.Zero) Marshal.FreeHGlobal(tokenInformation);
}
27
David Moore

ソリューションがVista UACで動作し、.Net Framework 3.5以上を使用していることを確認する場合は、System.DirectoryServices.AccountManagement名前空間を使用できます。コードは次のようになります。

bool isAllowed = false;
using (PrincipalContext pc = new PrincipalContext(ContextType.Machine, null))
{
    UserPrincipal up = UserPrincipal.Current;
    GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, "Administrators");
    if (up.IsMemberOf(gp))
        isAllowed = true;
}
17
Jacob Proffitt

Erwinのコードを試しましたが、コンパイルできませんでした。

このように動作するようになった:

[DllImport("Shell32.dll")] public static extern bool IsUserAnAdmin();
3
Alex G.

.NET Framework 4.5を使用すると、ユーザーが管理者グループに属しているかどうかを簡単に確認できるようです。

WindowsPrincipal principal = WindowsPrincipal.Current;
bool canBeAdmin = principal.Claims.Any((c) => c.Value == "S-1-5-32-544");
3
Jens

IsInRoleメソッドを利用する他の回答は、他の人がコメントしているように、ユーザーが昇格したトークンで実行している場合にのみtrueを返します。標準コンテキストと昇格コンテキストの両方でローカルのAdministratorsグループメンバーシップのみをチェックするための潜在的な代替手段を次に示します。

bool isAdmin = false;
using (var user = WindowsIdentity.GetCurrent())
{
    var principal = new WindowsPrincipal(user);
    // Check for token claim with well-known Administrators group SID
    const string LOCAL_ADMININSTRATORS_GROUP_SID = "S-1-5-32-544";
    if (principal.Claims.SingleOrDefault(x => x.Value == LOCAL_ADMININSTRATORS_GROUP_SID) != null)
    {
        isAdmin = true;
    }
}

return isAdmin;
2
Noah Stahl

このようなものでWMIを使用すると、アカウントが管理者であるかどうか、およびそのアカウントについて知りたいことを確認できます。

using System;
using System.Management;
using System.Windows.Forms;

namespace WMISample
{
    public class MyWMIQuery
    {
        public static void Main()
        {
            try
            {
                ManagementObjectSearcher searcher = 
                    new ManagementObjectSearcher("root\\CIMV2", 
                    "SELECT * FROM Win32_UserAccount"); 

                foreach (ManagementObject queryObj in searcher.Get())
                {
                    Console.WriteLine("-----------------------------------");
                    Console.WriteLine("Win32_UserAccount instance");
                    Console.WriteLine("-----------------------------------");
                    Console.WriteLine("AccountType: {0}", queryObj["AccountType"]);
                    Console.WriteLine("FullName: {0}", queryObj["FullName"]);
                    Console.WriteLine("Name: {0}", queryObj["Name"]);
                }
            }
            catch (ManagementException e)
            {
                MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
            }
        }
    }
}

ダウンロードを開始しやすくするために WMI Creator

また、これを使用して、Active Directory(LDAP)またはコンピューター/ネットワーク上の他の何かにアクセスできます。

1
Bob The Janitor

4つの可能な方法があります-私は好む:

(new WindowsPrincipal(WindowsIdentity.GetCurrent())).IsInRole(WindowsBuiltInRole.Administrator);

以下は、現在のユーザーのIDに関連するすべてのクレームデータのリストを提供するコードです。

注:WindowsPrincipal.Current。Claimsと(new WindowsPrincipal(WindowsIdentity.GetCurrent()))の間に返されるクレームリストには大きな違いがあります。Claims

Console.WriteLine("press the ENTER key to start listing user claims:");
Console.ReadLine();

Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
bool canBeAdmin = (new WindowsPrincipal(WindowsIdentity.GetCurrent())).IsInRole(WindowsBuiltInRole.Administrator);
Console.WriteLine("GetCurrent IsInRole: canBeAdmin:{0}", canBeAdmin);

Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
canBeAdmin = (new WindowsPrincipal(WindowsIdentity.GetCurrent())).Claims.Any((c) => c.Value == "S-1-5-32-544");
Console.WriteLine("GetCurrent Claim: canBeAdmin?:{0}", canBeAdmin);

Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
canBeAdmin = (new WindowsPrincipal(WindowsIdentity.GetCurrent())).IsInRole("Administrator");
Console.WriteLine("GetCurrent IsInRole \"Administrator\": canBeAdmin?:{0}", canBeAdmin);

Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
canBeAdmin = (new WindowsPrincipal(WindowsIdentity.GetCurrent())).IsInRole("Admin");
Console.WriteLine("GetCurrent IsInRole \"Admin\": canBeAdmin?:{0}", canBeAdmin);

Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
canBeAdmin = WindowsPrincipal.Current.IsInRole("Admin");
Console.WriteLine("Current IsInRole \"Admin\": canBeAdmin:{0}", canBeAdmin);


Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
canBeAdmin = WindowsPrincipal.Current.IsInRole("Administrator");
Console.WriteLine("Current IsInRole \"Administrator\": canBeAdmin:{0}", canBeAdmin);

Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
canBeAdmin = WindowsPrincipal.Current.Claims.Any((c) => c.Value == "S-1-5-32-544");
Console.WriteLine("Current Claim: canBeAdmin?:{0}", canBeAdmin);

Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
Console.WriteLine("WindowsPrincipal Claims:");
Console.WriteLine("---------------------");

var propertyCount = 0;
foreach (var claim in WindowsPrincipal.Current.Claims)
{
    Console.WriteLine("{0}", propertyCount++);
    Console.WriteLine("{0}", claim.ToString());
    Console.WriteLine("Issuer:{0}", claim.Issuer);
    Console.WriteLine("Subject:{0}", claim.Subject);
    Console.WriteLine("Type:{0}", claim.Type);
    Console.WriteLine("Value:{0}", claim.Value);
    Console.WriteLine("ValueType:{0}", claim.ValueType);
}

Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
Console.WriteLine("WindowsPrincipal Identities Claims");
Console.WriteLine("---------------------");

propertyCount = 0;
foreach (var identity in WindowsPrincipal.Current.Identities)
{
    int subPropertyCount = 0;
    foreach (var claim in identity.Claims)
    {
        Console.WriteLine("{0} {1}", propertyCount, subPropertyCount++);
        Console.WriteLine("{0}", claim.ToString());
        Console.WriteLine("Issuer:{0}", claim.Issuer);
        Console.WriteLine("Subject:{0}", claim.Subject);
        Console.WriteLine("Type:{0}", claim.Type);
        Console.WriteLine("Value:{0}", claim.Value);
        Console.WriteLine("ValueType:{0}", claim.ValueType);
    }
    Console.WriteLine();
    propertyCount++;
}

Console.WriteLine("---------------------");
Console.WriteLine("---------------------");
Console.WriteLine("Principal Id Claims");
Console.WriteLine("---------------------");

var p = new WindowsPrincipal(WindowsIdentity.GetCurrent());
foreach (var claim in (new WindowsPrincipal(WindowsIdentity.GetCurrent())).Claims)
{
    Console.WriteLine("{0}", propertyCount++);
    Console.WriteLine("{0}", claim.ToString());
    Console.WriteLine("Issuer:{0}", claim.Issuer);
    Console.WriteLine("Subject:{0}", claim.Subject);
    Console.WriteLine("Type:{0}", claim.Type);
    Console.WriteLine("Value:{0}", claim.Value);
    Console.WriteLine("ValueType:{0}", claim.ValueType);
}

Console.WriteLine("press the ENTER key to end");
Console.ReadLine();
0
OzBob

どうですか:

using System.Runtime.InteropServices;

internal static class Useful {
    [DllImport("Shell32.dll", EntryPoint = "IsUserAnAdmin")]
    public static extern bool IsUserAnAdministrator();
}
0
Erwin Mayer