Работающий пример .NET, использующий взаимодействие SetEntriesInAcl в действии - PullRequest
1 голос
/ 12 апреля 2011

Есть ли у кого-нибудь рабочий пример вызова метода SetEntriesInAcl в .NET с использованием P / Invoke?

Я продолжаю получать ошибку 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

Я буду рад использовать новый управляемый API для измененияAcl, если кто-то показывает мне, как, если мне нужно изменить Acl контейнера закрытого ключа, связанного с сертификатом.Неясно, как использовать управляемый API в этом сценарии.

Ответы [ 2 ]

1 голос
/ 12 апреля 2011

У меня нет ответа на ваш вопрос о взаимодействии, но .Net теперь поддерживает ACL в управляемом коде с использованием пространства имен System.Security.AccessControl. Пример см. http://msdn.microsoft.com/en-us/library/ms229078.aspx.

Это может быть проще, чем использование собственного взаимодействия.

0 голосов
/ 06 апреля 2016

У меня было такое же требование сделать это через вызовы Interop. Я нашел соответствующий ответ, который искал здесь:

(другой код ошибки, та же основная причина сбоя) Использование SetEntriesInAcl в C #: ошибка 1332

Это связано с поддержкой ANSI и Unicode, и вам нужно будет использовать правильный CharSet в определении метода P-Invoke.

[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 (например, типам wide-char в 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...