一个使用SetEntriesInAcl互操作的.NET实例

时间:2011-04-11 20:53:02

标签: .net security interop

有没有人有一个使用P / Invoke在.NET中调用SetEntriesInAcl方法的工作示例?

我在调用时一直收到错误87,但是我无法弄清楚我做错了什么。

以下是我的定义:

private enum FileAccessRights
{
  FILE_READ_DATA = 0x0001,
}
private enum AccessMode
{
  GRANT_ACCESS = 1,
  REVOKE_ACCESS = 4,
}

private enum InheritanceFlags
{
  NO_INHERITANCE = 0x0,
}

private enum TrusteeForm
{
  TRUSTEE_IS_SID = 0,
}

private enum TrusteeType
{
  TRUSTEE_IS_USER = 1,
}
private struct ExplicitAccess
{
  public FileAccessRights AccessPermissions;
  public AccessMode AccessMode;
  public InheritanceFlags Inheritance;
  public Trustee Trustee;
}

private struct Trustee
{
  public IntPtr MultipleTrustee;
  public int MultipleTrusteeOperation;
  public TrusteeForm TrusteeForm;
  public TrusteeType TrusteeType;
  [MarshalAs(UnmanagedType.LPWStr)]
  public string Name;
}
[DllImport("advapi32.dll", SetLastError = true)]
static extern int SetEntriesInAcl(int countOfExplicitEntries, ref ExplicitAccess explicitEntry, IntPtr oldAcl, out IntPtr newAcl);

以下是我如何调用它:

    SecurityIdentifier sid = GetSid();
    var ea = new ExplicitAccess
    {
      AccessPermissions = FileAccessRights.FILE_READ_DATA,
      AccessMode = AccessMode.GRANT_ACCESS,
      Inheritance = InheritanceFlags.NO_INHERITANCE,
      Trustee = new Trustee
      {
        TrusteeForm = TrusteeForm.TRUSTEE_IS_SID,
        TrusteeType = TrusteeType.TRUSTEE_IS_USER,
        Name = sid.Value
      }
    };

    IntPtr newAcl;
    int res = SetEntriesInAcl(1, ref ea, currentAcl, out newAcl);

我一直收到错误87(参数无效),不知道为什么。

非常感谢所有好撒玛利亚人。

EDIT1

如果有人告诉我如何修改与证书关联的私钥容器的Acl,我将很高兴使用新的托管API来更改Acl。目前还不清楚如何在这种情况下使用托管API。

2 个答案:

答案 0 :(得分:1)

我对你的Interop问题没有答案,但.Net现在使用System.Security.AccessControl命名空间支持托管代码中的ACL。有关示例,请参阅http://msdn.microsoft.com/en-us/library/ms229078.aspx

这可能比滚动您自己的互操作更容易使用。

答案 1 :(得分:0)

我有同样的要求通过Interop调用来做到这一点。我找到了我在这里搜索的相关答案:

(不同的错误代码,失败的相同根本原因) Using SetEntriesInAcl in C# : error 1332

它与ANSI与Uni​​code的支持有关,你需要在P-Invoke方法定义中使用正确的CharSet。

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern uint SetEntriesInAcl(
   int cCountOfExplicitEntries,
   ref EXPLICIT_ACCESS pListOfExplicitEntries,
   IntPtr OldAcl,
   out IntPtr NewAcl);

要确保的另一件事是CharSet对于所有结构和方法定义都是一致的。事实上,因为我们的服务在所有支持Unicode字符集的服务器上运行,所以我们将CharSet全部更改为CharSet.Unicode。

此外,我们需要确保我们编组字符串参数的非托管类型与Unicode字符集匹配(例如,C ++ / native中的宽字符类型)。下面我们使用UnmanagedType.LPWStr。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct TRUSTEE
{
    public IntPtr MultipleTrustee;
    public MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation;
    public TRUSTEE_FORM TrusteeForm;
    public TRUSTEE_TYPE TrusteeType;
    [MarshalAs(UnmanagedType.LPWStr)] public string Name;
}

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern uint GetNamedSecurityInfo(
     [MarshalAs(UnmanagedType.LPWStr)] string pObjectName,
     SE_OBJECT_TYPE ObjectType,
     SECURITY_INFORMATION SecurityInfo,
     out IntPtr pSidOwner,
     out IntPtr pSidGroup,
     out IntPtr pDacl,
     out IntPtr pSacl,
     out IntPtr pSecurityDescriptor);

(这是用于在共享路径上设置权限的工作代码,但它可能有助于您获得所需内容):

public static void SetReadOnlySharePermissions(string serverName, string shareName, string wellKnownGroupName, DfsSharePermission permissions)
    {
        IntPtr sidOwnerPtr = IntPtr.Zero;
        IntPtr groupOwnerPtr = IntPtr.Zero;
        IntPtr saclPtr = IntPtr.Zero;
        IntPtr oldDacl = IntPtr.Zero;
        IntPtr oldSecurityDescriptor = IntPtr.Zero;
        string shareObjectName = $@"\\{serverName}\{shareName}";

        uint securityObjectQueryResult = NetShareInterop.GetNamedSecurityInfo(
            shareObjectName,
            NetShareInterop.SE_OBJECT_TYPE.SE_LMSHARE,
            NetShareInterop.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION,
            out sidOwnerPtr,
            out groupOwnerPtr,
            out oldDacl,
            out saclPtr,
            out oldSecurityDescriptor);

        if (securityObjectQueryResult != 0)
        {
            throw new Win32Exception((int)securityObjectQueryResult);
        }

        // Default permissions = ReadOnly
        uint shareAccessPermissions = (uint)NetShareInterop.ACCESS_MASK.SHARE_ACCESS_READ;
        switch (permissions)
        {
            case DfsSharePermission.FullControl:
                shareAccessPermissions = (uint)NetShareInterop.ACCESS_MASK.SHARE_ACCESS_FULL;
                break;
            case DfsSharePermission.ReadWrite:
                shareAccessPermissions = (uint)NetShareInterop.ACCESS_MASK.SHARE_ACCESS_WRITE;
                break;
        }

        NetShareInterop.EXPLICIT_ACCESS access = new NetShareInterop.EXPLICIT_ACCESS()
        {
            AccessMode = (uint)NetShareInterop.ACCESS_MODE.SET_ACCESS,
            AccessPermissions = shareAccessPermissions,
            Inheritance = (uint)NetShareInterop.ACCESS_INHERITANCE.SUB_CONTAINERS_AND_OBJECTS_INHERIT,
            trustee = new NetShareInterop.TRUSTEE()
            {
                Name = wellKnownGroupName,
                TrusteeForm = NetShareInterop.TRUSTEE_FORM.TRUSTEE_IS_NAME,
                TrusteeType = NetShareInterop.TRUSTEE_TYPE.TRUSTEE_IS_WELL_KNOWN_GROUP
            }
        };

        IntPtr newDacl;
        int initializeAclEntriesResult = NetShareInterop.SetEntriesInAcl(1, ref access, oldDacl, out newDacl);
        if (initializeAclEntriesResult != 0)
        {
            throw new Win32Exception(initializeAclEntriesResult);
        }

        uint setSecurityResult = NetShareInterop.SetNamedSecurityInfo(
            shareObjectName,
            NetShareInterop.SE_OBJECT_TYPE.SE_LMSHARE,
            NetShareInterop.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION,
            IntPtr.Zero,
            IntPtr.Zero,
            newDacl,
            IntPtr.Zero);

        if (setSecurityResult != 0)
        {
            throw new Win32Exception((int)setSecurityResult);
        }
    }

(..为什么要让你挖掘所有那些愚蠢的互操作枚举和结构定义?)

internal static class NetShareInterop
{
    private const CharSet DefaultCharSet = CharSet.Unicode;

    internal enum ACCESS_MODE : uint
    {
        NOT_USED_ACCESS = 0,
        GRANT_ACCESS,
        SET_ACCESS,
        REVOKE_ACCESS,
        SET_AUDIT_SUCCESS,
        SET_AUDIT_FAILURE
    }

    internal enum ACCESS_MASK : uint
    {
        GENERIC_ALL = 0x10000000, //268435456,
        GENERIC_READ = 0x80000000, //2147483648L,
        GENERIC_WRITE = 0x40000000, //1073741824,
        GENERIC_EXECUTE = 0x20000000, //536870912,
        STANDARD_RIGHTS_READ = 0x00020000, //131072
        STANDARD_RIGHTS_WRITE = 0x00020000,
        SHARE_ACCESS_READ = 0x1200A9, // 1179817
        SHARE_ACCESS_WRITE = 0x1301BF, // 1245631
        SHARE_ACCESS_FULL = 0x1f01ff // 2032127
    }

    internal enum ACCESS_INHERITANCE : uint
    {
        NO_INHERITANCE = 0,
        OBJECT_INHERIT_ACE = 0x1,
        CONTAINER_INHERIT_ACE = 0x2,
        NO_PROPAGATE_INHERIT_ACE = 0x4,
        INHERIT_ONLY_ACE = 0x8,
        INHERITED_ACE = 0x10,
        SUB_OBJECTS_ONLY_INHERIT = ACCESS_INHERITANCE.OBJECT_INHERIT_ACE | ACCESS_INHERITANCE.INHERIT_ONLY_ACE,
        SUB_CONTAINERS_ONLY_INHERIT = ACCESS_INHERITANCE.CONTAINER_INHERIT_ACE | ACCESS_INHERITANCE.INHERIT_ONLY_ACE,
        SUB_CONTAINERS_AND_OBJECTS_INHERIT = ACCESS_INHERITANCE.CONTAINER_INHERIT_ACE | ACCESS_INHERITANCE.OBJECT_INHERIT_ACE,
    }

    internal enum MULTIPLE_TRUSTEE_OPERATION
    {
        NO_MULTIPLE_TRUSTEE,
        TRUSTEE_IS_IMPERSONATE
    }

    internal enum NetError : uint
    {
        NERR_Success = 0,
        NERR_UnknownDevDir = 0x00000844,
        NERR_RedirectedPath = 0x00000845,
        NERR_DuplicateShare = 0x00000846,
        NERR_NetNameNotFound = 0x00000906,
        NERR_DfsNoSuchVolume = 0x00000A66
    }

    internal enum SE_OBJECT_TYPE
    {
        SE_UNKNOWN_OBJECT_TYPE = 0,
        SE_FILE_OBJECT,
        SE_SERVICE,
        SE_PRINTER,
        SE_REGISTRY_KEY,
        SE_LMSHARE,
        SE_KERNEL_OBJECT,
        SE_WINDOW_OBJECT,
        SE_DS_OBJECT,
        SE_DS_OBJECT_ALL,
        SE_PROVIDER_DEFINED_OBJECT,
        SE_WMIGUID_OBJECT,
        SE_REGISTRY_WOW64_32KEY
    }

    [Flags]
    internal enum SECURITY_INFORMATION : uint
    {
        OWNER_SECURITY_INFORMATION = 0x00000001,
        GROUP_SECURITY_INFORMATION = 0x00000002,
        DACL_SECURITY_INFORMATION = 0x00000004,
        SACL_SECURITY_INFORMATION = 0x00000008,
        UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000,
        UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000,
        PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000,
        PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
    }

    internal enum SHARE_TYPE : uint
    {
        STYPE_DISKTREE = 0,
        STYPE_PRINTQ = 1,
        STYPE_DEVICE = 2,
        STYPE_IPC = 3,
        STYPE_TEMPORARY = 0x40000000,
        STYPE_SPECIAL = 0x80000000,
    }

    internal enum TRUSTEE_FORM
    {
        TRUSTEE_IS_SID = 0,
        TRUSTEE_IS_NAME,
        TRUSTEE_BAD_FORM,
        TRUSTEE_IS_OBJECTS_AND_SID,
        TRUSTEE_IS_OBJECTS_AND_NAME
    }

    internal enum TRUSTEE_TYPE
    {
        TRUSTEE_IS_UNKNOWN = 0,
        TRUSTEE_IS_USER,
        TRUSTEE_IS_GROUP,
        TRUSTEE_IS_DOMAIN,
        TRUSTEE_IS_ALIAS,
        TRUSTEE_IS_WELL_KNOWN_GROUP,
        TRUSTEE_IS_DELETED,
        TRUSTEE_IS_INVALID,
        TRUSTEE_IS_COMPUTER
    }

    [StructLayout(LayoutKind.Sequential, CharSet = DefaultCharSet)]
    internal struct SHARE_INFO_502
    {
        [MarshalAs(UnmanagedType.LPWStr)]
        public string shi502_netname;
        public SHARE_TYPE shi502_type;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string shi502_remark;
        public int shi502_permissions;
        public int shi502_max_uses;
        public int shi502_current_uses;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string shi502_path;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string shi502_passwd;
        public int shi502_reserved;
        public IntPtr shi502_security_descriptor;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = DefaultCharSet)]
    internal struct EXPLICIT_ACCESS
    {
        public uint AccessPermissions;
        public uint AccessMode;
        public uint Inheritance;
        public TRUSTEE trustee;
    }

    //Platform independent (32 & 64 bit) - use Pack = 0 for both platforms. IntPtr works as well.
    [StructLayout(LayoutKind.Sequential, CharSet = DefaultCharSet)]
    internal struct TRUSTEE
    {
        public IntPtr MultipleTrustee;
        public MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation;
        public TRUSTEE_FORM TrusteeForm;
        public TRUSTEE_TYPE TrusteeType;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string Name;
    }

    [DllImport("advapi32.dll", CharSet = DefaultCharSet, SetLastError = true)]
    internal static extern uint GetNamedSecurityInfo(
       [MarshalAs(UnmanagedType.LPWStr)] string pObjectName,
       SE_OBJECT_TYPE ObjectType,
       SECURITY_INFORMATION SecurityInfo,
       out IntPtr pSidOwner,
       out IntPtr pSidGroup,
       out IntPtr pDacl,
       out IntPtr pSacl,
       out IntPtr pSecurityDescriptor);

    [DllImport("Netapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern NetError NetShareAdd(

        [MarshalAs(UnmanagedType.LPWStr)] string strServer,
        Int32 dwLevel,
        ref SHARE_INFO_502 buf,
        out uint parm_err
    );

    [DllImport("netapi32.dll", CharSet = DefaultCharSet, SetLastError = true)]
    internal static extern NetError NetShareDel(
        [MarshalAs(UnmanagedType.LPWStr)] string strServer,
        [MarshalAs(UnmanagedType.LPWStr)] string strNetName,
        int reserved //must be 0
    );

    [DllImport("advapi32.dll", CharSet = DefaultCharSet, SetLastError = true)]
    internal static extern uint SetNamedSecurityInfo(
         [MarshalAs(UnmanagedType.LPWStr)] string pObjectName,
         SE_OBJECT_TYPE ObjectType,
         SECURITY_INFORMATION SecurityInfo,
         IntPtr psidOwner,
         IntPtr psidGroup,
         IntPtr pDacl,
         IntPtr pSacl);

    [DllImport("advapi32.dll", CharSet = DefaultCharSet, SetLastError = true)]
    internal static extern int SetEntriesInAcl(
         int cCountOfExplicitEntries,
         ref EXPLICIT_ACCESS pListOfExplicitEntries,
         IntPtr OldAcl,
         out IntPtr NewAcl);
}