Query recycle bin whilst impersonating user

3

Long story short, I'm trying to query the recycle bin as another user. This is a WPF app with a service, and I need to query the recycle bin within the service... I know... We need to use NetNamedPipeBinding, and can't use the OperationBehavior attribute.

Thus far, I've had success in my Windows 10 VM with the following method:

I've then tried the same code in a Windows XP VM, and I can't get it work. As soon as SHQueryRecycleBin is called, I get an message box display stating that:

The Recycle Bin on C:\ is corrupted. Do you want to empty the Recycle Bin for this drive?

I know this is not true, as I can query the recycle bin if I'm running as tester, and also view it via windows explorer.

This looks like a common issue, and I found a Microsoft KB article. This is listed under causes:

This problem can occur when the logical drive that is referenced is an NTFS drive and there was an error in a permissions-compare operation.

I believe all my problems are related to permissions. But this is where I'm stuck. I don't know why I don't have the necessary permissions, and don't have any idea how to troubleshoot this problem. Does anyone have any ideas?

I've tried using ProcessAccessFlags.All, TOKEN_ALL_ACCESS, and AdjustTokenPrivileges as a long shot, which didn't help.

I've been testing this with LINQPad, and using this SO answer to run LINQPad under the system account. For completeness here's a snippet which should copy / paste easily, and the output running under tester and system.

Running as tester:

OpenProcessToken returned 1
AdjustTokenPrivileges = True
Got user's token as 2264
Process running as XPTESTER\tester
Impersonating XPTESTER\tester
hresult=0, cbSize=20, i64Size=160420, i64NumItems=8

Running as system:

OpenProcessToken returned 1
AdjustTokenPrivileges = True
Got user's token as 2128
Process running as NT AUTHORITY\SYSTEM
Impersonating XPTESTER\tester
hresult=0, cbSize=20, i64Size=0, i64NumItems=0

Crude testing code:

void Main()
{
    string drive = "C:";
    uint pid = 1676;
    IntPtr userToken = DuplicateProcessToken(pid);

    LUID tLuid = new LUID();
    TOKEN_PRIVILEGES NewState = new TOKEN_PRIVILEGES();
    NewState.PrivilegeCount = 1;
    NewState.Privileges.pLuid = tLuid;
    NewState.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
    var adjustResult = AdjustTokenPrivileges(userToken, false, ref NewState, (uint)Marshal.SizeOf(NewState), IntPtr.Zero, IntPtr.Zero);
    Console.WriteLine("AdjustTokenPrivileges = {0}", adjustResult);

    Console.WriteLine("Got user's token as {0}", userToken);
    Console.WriteLine("Process running as {0}", WindowsIdentity.GetCurrent().Name);
    using(var impersonatedUser = WindowsIdentity.Impersonate(userToken))
    {
        var winIdentity = WindowsIdentity.GetCurrent();
        Console.WriteLine("Impersonating {0}", winIdentity.Name);   

        var result = new SHQUERYRBINFO();
        result.cbSize = Marshal.SizeOf(typeof(SHQUERYRBINFO));
        int hresult = SHQueryRecycleBin(drive, ref result);

        Console.WriteLine(
            "hresult={0}, cbSize={1}, i64Size={2}, i64NumItems={3}",
            hresult,
            result.cbSize,
            result.i64Size,
            result.i64NumItems);
    }
}

public const Int32 SE_PRIVILEGE_ENABLED = 0x00000002;

public static IntPtr DuplicateProcessToken(uint pid)
{
    IntPtr hProcess = OpenProcess(ProcessAccessFlags.All, 0, pid);  
    uint uPriv = TOKEN_ALL_ACCESS;  
    IntPtr token = IntPtr.Zero;
    int result = OpenProcessToken(hProcess, uPriv, ref token);
    Console.WriteLine("OpenProcessToken returned {0}", result);
    return token;
}

public const uint STANDARD_RIGHTS_REQUIRED = 0x00F0000;
public const uint STANDARD_RIGHTS_READ = 0x002000;
public const uint TOKEN_ASSIGN_PRIMARY = 0x0001;
public const uint TOKEN_DUPLICATE = 0x0002;
public const uint TOKEN_IMPERSONATE = 0x004;
public const uint TOKEN_QUERY = 0x0008;
public const uint TOKEN_QUERY_SOURCE = 0x0010;
public const uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
public const uint TOKEN_ADJUST_GROUPS = 0x0040;
public const uint TOKEN_ADJUST_DEFAULT = 0x0080;
public const uint TOKEN_ADJUST_SESSIONID = 0x0100;
public const uint TOKEN_READ = (STANDARD_RIGHTS_REQUIRED | TOKEN_QUERY);
public const uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED
    | TOKEN_ASSIGN_PRIMARY
    | TOKEN_DUPLICATE
    | TOKEN_IMPERSONATE
    | TOKEN_QUERY
    | TOKEN_QUERY_SOURCE
    | TOKEN_ADJUST_PRIVILEGES
    | TOKEN_ADJUST_GROUPS
    | TOKEN_ADJUST_DEFAULT
    | TOKEN_ADJUST_SESSIONID);

// Pack = 8 for x64
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct SHQUERYRBINFO
{
    public int cbSize;
    public long i64Size;
    public long i64NumItems;        
}

[DllImport("shell32.dll", SetLastError = true)]
private static extern int SHQueryRecycleBin(string pszRootPath, ref SHQUERYRBINFO pSHQueryRBInfo);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, int blnheritHanfle, uint dwAppProcessId);

[DllImport("advapi32.dll", SetLastError = true)]
public static extern int OpenProcessToken(IntPtr processHandle, uint desiredAccess, ref IntPtr tokenHandle);

[Flags]
public enum ProcessAccessFlags : uint
{
    All = 0x001F0FFF,
    Terminate = 0x00000001,
    CreateThread = 0x00000002,
    VMOperation = 0x00000008,
    VMRead = 0x00000010,
    VMWrite = 0x00000020,
    DupHandle = 0x00000040,
    SetInformation = 0x00000200,
    QueryInformation = 0x00000400,
    Synchronize = 0x00100000
}

[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AdjustTokenPrivileges(
    IntPtr TokenHandle,
    [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
    ref TOKEN_PRIVILEGES NewState,
    UInt32 BufferLength,
    IntPtr PreviousState,
    IntPtr ReturnLength);

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LUID
{
  public Int32 LowPart;
  public Int32 HighPart;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LUID_AND_ATTRIBUTES
{
  public LUID pLuid;
  public Int32 Attributes;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TOKEN_PRIVILEGES
{
  public Int32 PrivilegeCount;
  public LUID_AND_ATTRIBUTES Privileges;
}
c#
winapi
impersonation
asked on Stack Overflow May 31, 2016 by Darren Hale • edited May 23, 2017 by Community

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0