6

This code works fine with me:

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    [DllImport("kernel32.dll")]
    public static extern bool CloseHandle(IntPtr token);

enum LogonType
    {
        Interactive = 2,
        Network = 3,
        Batch = 4,
        Service = 5,
        Unlock = 7,
        NetworkClearText = 8,
        NewCredentials = 9
    }
    enum LogonProvider
    {
        Default = 0,
        WinNT35 = 1,
        WinNT40 = 2,
        WinNT50 = 3
    }

private void Button1_Click()
    { 
        IntPtr token = IntPtr.Zero;
        LogonUser("Administrator",
                  "192.168.1.244",
                  "PassWord",
                  (int)LogonType.NewCredentials,
                  (int)LogonProvider.WinNT50,
                  ref token);
        using (WindowsImpersonationContext context = WindowsIdentity.Impersonate(token))
        {
    CloseHandle(token);
    /*
    Code_of_Do_Something
    */
    }
}

BUT...This means I have to repeat the last code which inside "Button1_Click()" each time I need to do impersonation ( Doing something on the remote machine = server). So my question: Is it possible to do something like this illustration?: enter image description here

John Saunders
  • 160,644
  • 26
  • 247
  • 397
CrownFord
  • 709
  • 5
  • 15
  • 1
    use a delegate ? http://msdn.microsoft.com/en-us/library/aa288459%28v=vs.71%29.aspx – Unix von Bash Feb 01 '14 at 12:22
  • You can also return the context value (the WindowsIdentity.Impersonate) and handle the disposing yourself. – RvdK Feb 01 '14 at 12:23
  • 1
    Shouldn’t the `CloseHandle` go *after* the code? And in fact shouldn’t it be inside its own `finally` block so that it will always be executed? – Konrad Rudolph Feb 01 '14 at 12:24
  • Agreed. What evidence do you have for calling `CloseHandle` there? And if `WindowsIdentity.Impersonate()` fails then you never call it at all. – David Heffernan Feb 01 '14 at 12:29

2 Answers2

3

You can use delegates for this purpose. The easiest way is to use Action or Func. If you don't need a return value, use an Action:

private void RunImpersonated(Action act)
{
    IntPtr token = IntPtr.Zero;
    LogonUser("Administrator",
              "192.168.1.244",
              "PassWord",
              (int)LogonType.NewCredentials,
              (int)LogonProvider.WinNT50,
              ref token);
    try
    {
        using (WindowsImpersonationContext context = WindowsIdentity.Impersonate(token))
        {
            // Call action
            act();
        }
    }
    finally
    {
        CloseHandle(token);
    }
}

Note that there are lots of variations with generic type parameters that allow you to also provide parameters to Action or Func delegates in a strongly typed way. If you need an into parameter for instance, use Action<int> instead of just Action.

Also note that I created a finally block that closes the handle whether an exception occurs or not.

In order to call the function, you can use a lambda expression:

private void button1_Click(object sender, EventArgs e)
{
    RunImpersonated(() => {
        DirectoryInfo dir = new DirectoryInfo( @"\\192.168.1.244\repository");
        foreach (DirectoryInfo di in dir.GetDirectories()) 
        { 
            lable_folders_count.Text = Convert.ToString(dir.GetFileSystemInfos().Length); 
        }
    });
}
Nathan Hanna
  • 4,643
  • 3
  • 28
  • 32
Markus
  • 20,838
  • 4
  • 31
  • 55
  • May I know to to put this code inside an Action? `code` DirectoryInfo dir = new DirectoryInfo( @"\\192.168.1.244\repository\); foreach (DirectoryInfo di in dir.GetDirectories()) { lable_folders_count.Text = Convert.ToString(dir.GetFileSystemInfos().Length); }`code` – CrownFord Feb 01 '14 at 18:42
  • @CrownFord: I updated the post and included a sample. Hope that it helps. – Markus Feb 01 '14 at 19:06
  • I got this Error: "Method must have a return type" Regarding: RunImpersonated(() – CrownFord Feb 01 '14 at 20:20
  • @CrownFord: where is the error shown? At public **void** RunImpersonated(Action act) or where you call RunImpersonated? – Markus Feb 01 '14 at 20:30
  • check the screen-capture from here, please: [link](http://www.fa6er.com/ad/error.png) – CrownFord Feb 01 '14 at 20:42
  • @CrownFord: you need to call RunImpersonated from another method, e.g. in the event handler of button1. I've updated the sample. – Markus Feb 01 '14 at 21:00
1

Yes, it is possible to pass code as a parameter. But let's solve your problem without using lambdas:

private void Button1_Click()
{
    using(GetImpersonationContext())
    {
        /* code here */
    } 
}
private WindowsImpersonationContext GetImpersonationContext()
{
    IntPtr token = IntPtr.Zero;
    LogonUser("Administrator",
              "192.168.1.244",
              "PassWord",
              (int)LogonType.NewCredentials,
              (int)LogonProvider.WinNT50,
              ref token);

    WindowsImpersonationContext context = WindowsIdentity.Impersonate(token);
    CloseHandle(token);
    return context;
}
Jacob Krall
  • 28,341
  • 6
  • 66
  • 76
  • it works fine, thanx... just need to remove one of the last double from`));` form `WindowsIdentity.Impersonate(token);` – CrownFord Feb 04 '14 at 01:10