C# Programmatic Remote Folder / File Authentication In Non-Domain Windows Environment
Asked Answered
A

1

4

I need to be able to programmatically authenticate when trying to read and write files on a remote computer in a non-domain environment.

When you type a command into the Windows RUN prompt that is similar to \\targetComputer\C$\targetFolder or \\targetComputer\admin$, where the targetComputer is NOT on a domain, you will be prompted to enter a username and password. Once you enter the username and password, you have full access to the remote folder.

How can I accomplish this authentication programmatically in C#?

I've tried..

--Impersonation, but it appears to only work in a domain environment.

--CMDKEY.exe, but it also seems to only work in a domain environment.

There must be a way to do this, but I have searched high and low with no luck so far. Maybe I'm just looking for the wrong thing? I'm sure I'm not the first to have this question. Any help would be greatly appreciated.

Thanks!

EDIT :

I think I just found a different SO posting that answers my question: Accessing a Shared File (UNC) From a Remote, Non-Trusted Domain With Credentials

I will work with that for now and see where it gets me.

Thanks!

Aria answered 20/6, 2013 at 18:48 Comment(1)
I think I just found a different SO posting that answers my question: Accessing a Shared File (UNC) From a Remote, Non-Trusted Domain With Credentials I will work with that for now and see where it gets me. Thanks!Aria
W
13

Impersonation works with Peer/LAN network as well. I got your typical home network with some machines on default "Workgroup" and some on a named one if I remembered doing it on the install.

Here is the code I use from my IIS server app to access files on my other computer (without having to have the same user and password on both machines involved, copied from somewhere and modified for my use):

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.ComponentModel;

/// <summary>
/// Class to impersonate another user. Requires user, pass and domain/computername
/// All code run after impersonationuser has been run will run as this user.
/// Remember to Dispose() afterwards.
/// </summary>
public class ImpersonateUser:IDisposable {

    private WindowsImpersonationContext LastContext = null;
    private IntPtr LastUserHandle = IntPtr.Zero;

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

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateLoggedOnUser(int Token);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool DuplicateToken(IntPtr token, int impersonationLevel, ref IntPtr duplication);

    [DllImport("kernel32.dll")]
    public static extern Boolean CloseHandle(IntPtr hObject);

    public const int LOGON32_PROVIDER_DEFAULT = 0;
    public const int LOGON32_PROVIDER_WINNT35 = 1;
    public const int LOGON32_LOGON_INTERACTIVE = 2;
    public const int LOGON32_LOGON_NETWORK = 3;
    public const int LOGON32_LOGON_BATCH = 4;
    public const int LOGON32_LOGON_SERVICE = 5;
    public const int LOGON32_LOGON_UNLOCK = 7;
    public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;// Win2K or higher
    public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;// Win2K or higher
    #endregion

    public ImpersonateUser(string username, string domainOrComputerName, string password, int nm = LOGON32_LOGON_NETWORK) {

        IntPtr userToken = IntPtr.Zero;
        IntPtr userTokenDuplication = IntPtr.Zero;

        bool loggedOn = false;

        if (domainOrComputerName == null) domainOrComputerName = Environment.UserDomainName;

        if (domainOrComputerName.ToLower() == "nt authority") {
            loggedOn = LogonUser(username, domainOrComputerName, password, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, out userToken);
        } else {
            loggedOn = LogonUser(username, domainOrComputerName, password, nm, LOGON32_PROVIDER_DEFAULT, out userToken);
        }

        WindowsImpersonationContext _impersonationContext = null;
        if (loggedOn) {
            try {
                // Create a duplication of the usertoken, this is a solution
                // for the known bug that is published under KB article Q319615.
                if (DuplicateToken(userToken, 2, ref userTokenDuplication)) {
                    // Create windows identity from the token and impersonate the user.
                    WindowsIdentity identity = new WindowsIdentity(userTokenDuplication);
                    _impersonationContext = identity.Impersonate();
                } else {
                    // Token duplication failed!
                    // Use the default ctor overload
                    // that will use Mashal.GetLastWin32Error();
                    // to create the exceptions details.
                    throw new Win32Exception();
                }
            } finally {
                // Close usertoken handle duplication when created.
                if (!userTokenDuplication.Equals(IntPtr.Zero)) {
                    // Closes the handle of the user.
                    CloseHandle(userTokenDuplication);
                    userTokenDuplication = IntPtr.Zero;
                }

                // Close usertoken handle when created.
                if (!userToken.Equals(IntPtr.Zero)) {
                    // Closes the handle of the user.
                    CloseHandle(userToken);
                    userToken = IntPtr.Zero;
                }
            }
        } else {
            // Logon failed!
            // Use the default ctor overload that 
            // will use Mashal.GetLastWin32Error();
            // to create the exceptions details.
            throw new Win32Exception();
        }

        if (LastContext == null) LastContext = _impersonationContext;
    }

    public void Dispose() {
        LastContext.Undo();
        LastContext.Dispose();
    }
}

The specific code I found out worked after a bit of trying was this:

using (var impersonation = new ImpersonateUser("OtherMachineUser", "OtherMachineName", "Password", LOGON32_LOGON_NEW_CREDENTIALS))
    {
        var files = System.IO.Directory.GetFiles("\\OtherMachineName\fileshare");
    }
Weissman answered 25/7, 2013 at 20:22 Comment(12)
I was able to use the following code to solve my problem: #659513. However, I'm curious to test your code later (I think I actually might have... feel like I saw that code on SO before I posted this question) and see how it compares to my original impersonation code. First glance of your code is that it looks just like the code I was using previously with only success in domain environments. I will look at it more closely later. Thanks.Aria
The key is: LOGON32_LOGON_NEW_CREDENTIALS. I tried all the different choices and LOGON32_LOGON_NEW_CREDENTIALS was the one that worked. The rest of the code is generic.Weissman
Very interesting. I will definitely try it out and report back. Thanks!Aria
This code worked for me as well, though I was solving a slightly different problem. My goal was to access a file on a network folder that used a different domain than my local machine. Amazingly, despite the dll imports, it worked right out of the box!Prehuman
I had forgotten to report back but just wanted to say that this code seems to work great. Thanks again!Aria
Can a non shared file/folder be access using this method?Eldwon
It's just impersonation so yes it can be used locally to access files under different credentials. It can not access files on another computer that has not been shared in anyway.Weissman
Once I accessed the files by using above code . After then how i will remove access of shared folder? . Because during access shared folder in Window it will stored user Id and Password in Cache. So is there any need to remove that Cache ?Breslau
I am not aware of any caching mechanism with this method. I would assume no caching is happening. Caching happens when you get a popup in windows and enter credentials and check "Remember my credentials". Just test running the code and check the Credentials Manager to see if any new entries has been added.Weissman
can you provide a valid filepath of the remote machine? my machine name is Server and I need to access D drive on it, I am getting an error when I try: var files = System.IO.Directory.GetFiles("\\Server\\D:");Motoring
ummm. That is not a valid network path. Go share a folder or drive on the server, open it via Explorer and copy the path and use it in your program. Like \\server\myshare or \\server\d (IF u shared the d: disk as "d")Weissman
When i access remote pc shared directory an error came "Device is not ready"Decury

© 2022 - 2024 — McMap. All rights reserved.