6

对于应用程序,我要检查特定用户是否具有作为服务登录的权利?如何以编程方式执行此操作?我上网查了一下,没找到好的资源

谢谢

上普尔

4

4 回答 4

16

我检查了所有以前的答案和相关帖子中的许多其他答案,花了 3 天时间深入研究 Win32 API,但没有得到这个问题的可靠答案(一些抛出异常,一些即使尝试修复它们也没有编译,一些仅适用于本地帐户)。最后,我找到了可以接受的答案。作为基础,我在technet 论坛上使用了 Wieger1983 的答案。我对其进行了一些更改:

  • 对纯 C# 的轻微改编(最初它被声明为 powershell 扩展)
  • 增加稳定性(如果用户没有权限,它现在不会返回错误代码 2。@David Woodwart 在这篇文章中提供了解释:LsaEnumerateAccountRights 总是返回 "File not found")。
  • 在任何不可预知的异常情况下防止内存泄漏。现在在 finally 块中调用 CloseHandle。

现在它适用于本地和活动目录帐户,并且如果用户没有权限,则可以正常工作。我希望它能为像我这样的人节省时间=)。

警告:如果您将在 x64 架构上使用此代码,请注意下面 EricRRichards 的评论。我现在无法验证是否应该在每种情况下都应用它。

//
// This code has been adapted from http://www.codeproject.com/KB/cs/lsadotnet.aspx
// The rights enumeration code came from http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.interop/2004-11/0394.html
//
// Windows Security via .NET is covered on by Pluralsight:http://alt.pluralsight.com/wiki/default.aspx/Keith.GuideBook/HomePage.html
//

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

namespace LSA
{
    //
    // Provides methods the local security authority which controls user rights. Managed via secpol.msc normally.
    //
    public class LocalSecurityAuthorityController
    {
        private const int Access = (int)(
                                             LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
                                             LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
                                             LSA_AccessPolicy.POLICY_CREATE_PRIVILEGE |
                                             LSA_AccessPolicy.POLICY_CREATE_SECRET |
                                             LSA_AccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
                                             LSA_AccessPolicy.POLICY_LOOKUP_NAMES |
                                             LSA_AccessPolicy.POLICY_NOTIFICATION |
                                             LSA_AccessPolicy.POLICY_SERVER_ADMIN |
                                             LSA_AccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
                                             LSA_AccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
                                             LSA_AccessPolicy.POLICY_TRUST_ADMIN |
                                             LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
                                             LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION
                                         );

        [DllImport("advapi32.dll", PreserveSig = true)]
        private static extern UInt32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess, out IntPtr PolicyHandle);

        [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
        private static extern uint LsaAddAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING[] UserRights, int CountOfRights);

        [DllImport("advapi32")]
        public static extern void FreeSid(IntPtr pSid);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
        private static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName, ref int cbdomainLength, ref int use);

        [DllImport("advapi32.dll")]
        private static extern bool IsValidSid(IntPtr pSid);

        [DllImport("advapi32.dll")]
        private static extern int LsaClose(IntPtr ObjectHandle);

        [DllImport("kernel32.dll")]
        private static extern int GetLastError();

        [DllImport("advapi32.dll")]
        private static extern int LsaNtStatusToWinError(uint status);

        [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
        private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, out IntPtr UserRightsPtr, out int CountOfRights);

        [StructLayout(LayoutKind.Sequential)]
        private struct LSA_UNICODE_STRING
        {
            public UInt16 Length;
            public UInt16 MaximumLength;
            public IntPtr Buffer;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct LSA_OBJECT_ATTRIBUTES
        {
            public int Length;
            public IntPtr RootDirectory;
            public LSA_UNICODE_STRING ObjectName;
            public UInt32 Attributes;
            public IntPtr SecurityDescriptor;
            public IntPtr SecurityQualityOfService;
        }

        [Flags]
        private enum LSA_AccessPolicy : long
        {
            POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L,
            POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
            POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
            POLICY_TRUST_ADMIN = 0x00000008L,
            POLICY_CREATE_ACCOUNT = 0x00000010L,
            POLICY_CREATE_SECRET = 0x00000020L,
            POLICY_CREATE_PRIVILEGE = 0x00000040L,
            POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
            POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
            POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
            POLICY_SERVER_ADMIN = 0x00000400L,
            POLICY_LOOKUP_NAMES = 0x00000800L,
            POLICY_NOTIFICATION = 0x00001000L
        }

        // Returns the Local Security Authority rights granted to the account
        public IList<string> GetRights(string accountName)
        {
            IList<string> rights = new List<string>();
            string errorMessage = string.Empty;

            long winErrorCode = 0;
            IntPtr sid = IntPtr.Zero;
            int sidSize = 0;
            StringBuilder domainName = new StringBuilder();
            int nameSize = 0;
            int accountType = 0;

            LookupAccountName(string.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);

            domainName = new StringBuilder(nameSize);
            sid = Marshal.AllocHGlobal(sidSize);

            if (!LookupAccountName(string.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType))
            {
                winErrorCode = GetLastError();
                errorMessage = ("LookupAccountName failed: " + winErrorCode);
                throw new Win32Exception((int)winErrorCode, errorMessage);
            }
            else
            {
                LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();

                IntPtr policyHandle = IntPtr.Zero;
                IntPtr userRightsPtr = IntPtr.Zero;
                int countOfRights = 0;

                LSA_OBJECT_ATTRIBUTES objectAttributes = CreateLSAObject();

                uint policyStatus = LsaOpenPolicy(ref systemName, ref objectAttributes, Access, out policyHandle);
                winErrorCode = LsaNtStatusToWinError(policyStatus);

                if (winErrorCode != 0)
                {
                    errorMessage = string.Format("OpenPolicy failed: {0}.", winErrorCode);
                    throw new Win32Exception((int)winErrorCode, errorMessage);
                }
                else
                {
                    try
                    {
                        uint result = LsaEnumerateAccountRights(policyHandle, sid, out userRightsPtr, out countOfRights);
                        winErrorCode = LsaNtStatusToWinError(result);
                        if (winErrorCode != 0)
                        {
                            if (winErrorCode == 2)
                            {
                                return new List<string>();
                            }
                            errorMessage = string.Format("LsaEnumerateAccountRights failed: {0}", winErrorCode);
                            throw new Win32Exception((int)winErrorCode, errorMessage);
                        }

                        Int32 ptr = userRightsPtr.ToInt32();
                        LSA_UNICODE_STRING userRight;

                        for (int i = 0; i < countOfRights; i++)
                        {
                            userRight = (LSA_UNICODE_STRING)Marshal.PtrToStructure(new IntPtr(ptr), typeof(LSA_UNICODE_STRING));
                            string userRightStr = Marshal.PtrToStringAuto(userRight.Buffer);
                            rights.Add(userRightStr);
                            ptr += Marshal.SizeOf(userRight);
                        }
                    }
                    finally
                    {
                        LsaClose(policyHandle);
                    }
                }
                FreeSid(sid);
            }
            return rights;
        }

        // Adds a privilege to an account
        public void SetRight(string accountName, string privilegeName)
        {
            long winErrorCode = 0;
            string errorMessage = string.Empty;

            IntPtr sid = IntPtr.Zero;
            int sidSize = 0;
            StringBuilder domainName = new StringBuilder();
            int nameSize = 0;
            int accountType = 0;

            LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);

            domainName = new StringBuilder(nameSize);
            sid = Marshal.AllocHGlobal(sidSize);

            if (!LookupAccountName(string.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType))
            {
                winErrorCode = GetLastError();
                errorMessage = string.Format("LookupAccountName failed: {0}", winErrorCode);
                throw new Win32Exception((int)winErrorCode, errorMessage);
            }
            else
            {
                LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
                IntPtr policyHandle = IntPtr.Zero;
                LSA_OBJECT_ATTRIBUTES objectAttributes = CreateLSAObject();

                uint resultPolicy = LsaOpenPolicy(ref systemName, ref objectAttributes, Access, out policyHandle);
                winErrorCode = LsaNtStatusToWinError(resultPolicy);

                if (winErrorCode != 0)
                {
                    errorMessage = string.Format("OpenPolicy failed: {0} ", winErrorCode);
                    throw new Win32Exception((int)winErrorCode, errorMessage);
                }
                else
                {
                    try
                    {
                        LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
                        userRights[0] = new LSA_UNICODE_STRING();
                        userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
                        userRights[0].Length = (UInt16)(privilegeName.Length * UnicodeEncoding.CharSize);
                        userRights[0].MaximumLength = (UInt16)((privilegeName.Length + 1) * UnicodeEncoding.CharSize);

                        uint res = LsaAddAccountRights(policyHandle, sid, userRights, 1);
                        winErrorCode = LsaNtStatusToWinError(res);
                        if (winErrorCode != 0)
                        {
                            errorMessage = string.Format("LsaAddAccountRights failed: {0}", winErrorCode);
                            throw new Win32Exception((int)winErrorCode, errorMessage);
                        }
                    }
                    finally
                    {
                        LsaClose(policyHandle);
                    }
                }
                FreeSid(sid);
            }
        }

        private static LSA_OBJECT_ATTRIBUTES CreateLSAObject()
        {
            LSA_OBJECT_ATTRIBUTES newInstance = new LSA_OBJECT_ATTRIBUTES();

            newInstance.Length = 0;
            newInstance.RootDirectory = IntPtr.Zero;
            newInstance.Attributes = 0;
            newInstance.SecurityDescriptor = IntPtr.Zero;
            newInstance.SecurityQualityOfService = IntPtr.Zero;

            return newInstance;
        }
    }

    // Local security rights managed by the Local Security Authority
    public class LocalSecurityAuthorityRights
    {
        // Log on as a service right
        public const string LogonAsService = "SeServiceLogonRight";
        // Log on as a batch job right
        public const string LogonAsBatchJob = "SeBatchLogonRight";
        // Interactive log on right
        public const string InteractiveLogon = "SeInteractiveLogonRight";
        // Network log on right
        public const string NetworkLogon = "SeNetworkLogonRight";
        // Generate security audit logs right
        public const string GenerateSecurityAudits = "SeAuditPrivilege";
    }

    /* added wrapper for PowerShell */

    public class LSAWrapper
    {
        public static IList<string> GetRights(string accountName)
        {
            return new LocalSecurityAuthorityController().GetRights(accountName);
        }

        public static void SetRight(string accountName, string privilegeName)
        {
            new LocalSecurityAuthorityController().SetRight(accountName, privilegeName);
        }
    }
}

最后很容易检查权限:

var rights = LSAWrapper.GetRights("myMachineName\\TestUser");
if (rights.Contains(LocalSecurityAuthorityRights.LogonAsService))
{
    Console.WriteLine("User has right to logon as a service");
}
else
{
    Console.WriteLine("User doesn't have right to logon as a service");
}

更新:还要检查@robertburke 的答案——他似乎在 x64 支持和内存管理方面提出了很好的改进。

于 2014-01-20T15:57:34.233 回答
1

您有该帐户的令牌吗?如果是这样,您可以使用GetTokenInformationTokenInformationClass == TokenPrivileges调用。这将返回与令牌关联的权限列表以及它们是否已被激活。

如果该帐户未登录,因此您无法获得他们的令牌,则变得更加困难。您无法查询该帐户允许的权限,更不用说该帐户的任何组带入令牌的权限了。您需要登录帐户以检索令牌,然后按照之前的建议进行操作。

于 2011-02-18T05:58:07.720 回答
1

对 Sasha 解决方案的编辑:

对于 32/64 位可移植性,您不需要使用不同的代码或使用不安全的代码。而是使用:

                LSA_UNICODE_STRING userRight;

                for (int i = 0; i < countOfRights; i++)
                {
                    var indexPointer = IntPtr.Add(userRightsPtr, i * Marshal.SizeOf(typeof(LSA_UNICODE_STRING)));
                    userRight = (LSA_UNICODE_STRING)Marshal.PtrToStructure(indexPointer, typeof(LSA_UNICODE_STRING));
                    string userRightStr = Marshal.PtrToStringAuto(userRight.Buffer);
                    rights.Add(userRightStr);
                }

                LsaFreeMemory(userRightsPtr);

此外,使用 LsaFreeMemory 在完成后释放 userRightsPtr。请参阅LsaEnumerateAccountRights 的文档。这表明您必须使用 LsaFreeMemory 释放 LsaEnumerateAccountRights 返回的用户权限指针。

    [DllImport("advapi32.dll")]
    private static extern int LsaFreeMemory(IntPtr ObjectHandle);

另外,对于内置机器帐户,只需传递不带域的用户名,例如:IIS_IUSRS

于 2020-04-16T04:30:46.947 回答
0

看看使用

WindowsIdentity.GetCurrent 方法WindowsPrincipal 类

于 2011-02-18T05:47:22.913 回答