Technolog

Blogging over technologie.
Welcome to Technolog Sign in | Join | Help
in Search

eprogrammer

Howto: Properly use the AccessCheck API for the current user

I've seen people pulling the hair out for not getting this API workign for them.

The API, even if impersonating the current user, returns error 1309. "An attempt has been made to operate on an impersonation token by a thread that is not currently impersonating a client."

The clue is that this API, (and this is not clearly documented on the MSDN) needs a duplicated handle.

Anyway, spare your hair, have fun with the code. B.t.w. You can hire me for smart code and research on components etc..

http://www.adccure.nl for contact.

    [StructLayout(LayoutKind.Sequential)]

    internal struct GENERIC_MAPPING

    {

        internal uint GenericRead;

        internal uint GenericWrite;

        internal uint GenericExecute;

        internal uint GenericAll;

    }

    [DllImport("advapi32.dll", SetLastError = false)]

    static extern void MapGenericMask([In, MarshalAs(UnmanagedType.U4)] ref TokenAccessLevels AccessMask,

        [In] ref GENERIC_MAPPING map);

   

    [DllImport("advapi32.dll", SetLastError = true)]

    [return: MarshalAs(UnmanagedType.Bool)]

    public static extern bool DuplicateToken(IntPtr ExistingTokenHandle,

            [MarshalAs(UnmanagedType.U4)] TokenImpersonationLevel level,

            out int DuplicateTokenHandle);

    [DllImport("advapi32.dll", SetLastError = true)]       

     [return: MarshalAs(UnmanagedType.Bool)] static extern bool AccessCheck(

      [MarshalAs(UnmanagedType.LPArray)]

        byte[] pSecurityDescriptor, 

      IntPtr ClientToken,

      [MarshalAs(UnmanagedType.U4)]

        TokenAccessLevels accessmask,

      [In] ref GENERIC_MAPPING GenericMapping,

      IntPtr PrivilegeSet,

      ref int PrivilegeSetLength,

      out uint GrantedAccess,

      [MarshalAs(UnmanagedType.Bool)]

      out bool AccessStatus);

    [DllImport("kernel32")]

    static extern void CloseHandle(IntPtr ptr);

  internal static bool hasReadAccess(string path)

    {

        // Obtain the authenticated user's Identity

       

        WindowsIdentity winId = WindowsIdentity.GetCurrent(TokenAccessLevels.Duplicate | TokenAccessLevels.Query);

       

        WindowsImpersonationContext ctx = null;

        int statError = 0;

        IntPtr dupToken = IntPtr.Zero;

        try

        {

            // Start impersonating

            //ctx = winId.Impersonate(); works but AccessCheck does not like this

           

            int outPtr;

            //AccessCheck needs a duplicated token!

            DuplicateToken(winId.Token, TokenImpersonationLevel.Impersonation, out outPtr);

           

            dupToken = new IntPtr(outPtr);

            ctx = WindowsIdentity.Impersonate(dupToken);                

            Folder.GENERIC_MAPPING map = new Folder.GENERIC_MAPPING();

            map.GenericRead = 0x80000000;

            map.GenericWrite = 0x40000000;

            map.GenericExecute = 0x20000000;

            map.GenericAll = 0x10000000;

            TokenAccessLevels required = TokenAccessLevels.Query | TokenAccessLevels.Read | TokenAccessLevels.AssignPrimary | (TokenAccessLevels)0x00100000; // add synchronization

            MapGenericMask(ref required, ref map);

           

           

            uint status = 0;

            bool accesStatus = false;

            // dummy area the size should be 20 we don't do anything with it

            int sizeps = 20;

            IntPtr ps = Marshal.AllocCoTaskMem(sizeps);

           

            //AccessControlSections.Owner | AccessControlSections.Group MUST be included,

            //otherwise the descriptor would be seen with ERROR 1338

            var ACE = Directory.GetAccessControl(path,

                AccessControlSections.Access | AccessControlSections.Owner |

                    AccessControlSections.Group);

           

            bool success = AccessCheck(ACE.GetSecurityDescriptorBinaryForm(), dupToken, required, ref map,

                    ps, ref sizeps, out status, out accesStatus);

            Marshal.FreeCoTaskMem(ps);

            if (!success)

            {

                statError = Marshal.GetLastWin32Error();

            }

            else

            {

                return accesStatus;

            }

        }

        // Prevent exceptions from propagating

        catch (Exception ex)

        {

            Trace.Write(ex.Message);

        }

        finally

        {

            // Revert impersonation

           

            if (ctx != null)

                ctx.Undo();

            CloseHandle(dupToken);

        }

        if (statError != 0)

        {

            throw new Win32Exception(statError);

        }

       

        return false;

    }

This code is just a cut and paste. You can make it pretty.

Published Thursday, June 18, 2009 11:50 PM by eprogrammer

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Submit

About eprogrammer

Egbert Nierop is enthousiast C# en ASP.NET evangelist . Egbert Nierop is zelfstandige en houdt van projecten met een hoog technologische uitdaging.
Powered by Community Server, by Telligent Systems