copy files with authentication in c#
Asked Answered
G

5

11

I am trying to copy file from local drive to one of folder on server. name of the folder on server is 'DBFiles'. No one has got access to this apart from username 'user' and password 'password1!'

before coping the file, it creates the directory if not exisits as well.

can someone help to get access while creating directory 'Test' and then copy a files.

if (!Directory.Exists(@"\\server-a\copiedfiles\"))
    Directory.CreateDirectory(@"\\server-a\DBFiles\"+Test);   
File.Copy("C:\Temp\abc.txt", @"\\server-a\DBFiles\");

This is the original code in c#.

NetworkShare.DisconnectFromShare(@"\\server-a\DBFiles", true); //Disconnect in case we are currently connected with our credentials;
NetworkShare.ConnectToShare(@"\\server-a\DBFiles", "user1", "password1!"); //Connect with the new credentials

File.Copy(@"c:\temp\T1.txt", @"\\server-a\DBFiles\T1.txt");

NetworkShare.DisconnectFromShare(@"\\server-a\DBFiles", false); //Disconnect from the server.

Its giving error as Access Denied.

Gook answered 22/7, 2013 at 11:8 Comment(7)
And what are you having a problem doing? Not knowing how to authenticate to the share? Getting a exception while it is running? the file copy not coping all the bytes?Mesencephalon
Are you having permission issues? Maybe you should run your application with permission to the folder DBFilesUniformed
Just noticed, your Exists check and your CreateDirectory command are talking to two different shares on \\server-a, is that supposed to happen?Mesencephalon
I am getting access denied error message when trying to copy file. It was working fine before authentication access is needed. Here I need to put username and password to access folder.Gook
possible duplicate of Accessing Password Protected Network Drives in Windows in C#?Mesencephalon
Duplicate - #296038Ichthyosaur
See StackOverflow answer to this question here: Impersonate User for File Copy over NetworkDeclivous
M
29

Another option is you can programmaticly access the NET USE api of windows and authenticate to the share like if you went to it in explorer and typed in the credientals.

public static class NetworkShare
{
    /// <summary>
    /// Connects to the remote share
    /// </summary>
    /// <returns>Null if successful, otherwise error message.</returns>
    public static string ConnectToShare(string uri, string username, string password)
    {
        //Create netresource and point it at the share
        NETRESOURCE nr = new NETRESOURCE();
        nr.dwType = RESOURCETYPE_DISK;
        nr.lpRemoteName = uri;

        //Create the share
        int ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);

        //Check for errors
        if (ret == NO_ERROR)
            return null;
        else
            return GetError(ret);
    }

    /// <summary>
    /// Remove the share from cache.
    /// </summary>
    /// <returns>Null if successful, otherwise error message.</returns>
    public static string DisconnectFromShare(string uri, bool force)
    {
        //remove the share
        int ret = WNetCancelConnection(uri, force);

        //Check for errors
        if (ret == NO_ERROR)
            return null;
        else
            return GetError(ret);
    }

    #region P/Invoke Stuff
    [DllImport("Mpr.dll")]
    private static extern int WNetUseConnection(
        IntPtr hwndOwner,
        NETRESOURCE lpNetResource,
        string lpPassword,
        string lpUserID,
        int dwFlags,
        string lpAccessName,
        string lpBufferSize,
        string lpResult
        );

    [DllImport("Mpr.dll")]
    private static extern int WNetCancelConnection(
        string lpName,
        bool fForce
        );

    [StructLayout(LayoutKind.Sequential)]
    private class NETRESOURCE
    {
        public int dwScope = 0;
        public int dwType = 0;
        public int dwDisplayType = 0;
        public int dwUsage = 0;
        public string lpLocalName = "";
        public string lpRemoteName = "";
        public string lpComment = "";
        public string lpProvider = "";
    }

    #region Consts
    const int RESOURCETYPE_DISK = 0x00000001;
    const int CONNECT_UPDATE_PROFILE = 0x00000001;
    #endregion

    #region Errors
    const int NO_ERROR = 0;

    const int ERROR_ACCESS_DENIED = 5;
    const int ERROR_ALREADY_ASSIGNED = 85;
    const int ERROR_BAD_DEVICE = 1200;
    const int ERROR_BAD_NET_NAME = 67;
    const int ERROR_BAD_PROVIDER = 1204;
    const int ERROR_CANCELLED = 1223;
    const int ERROR_EXTENDED_ERROR = 1208;
    const int ERROR_INVALID_ADDRESS = 487;
    const int ERROR_INVALID_PARAMETER = 87;
    const int ERROR_INVALID_PASSWORD = 1216;
    const int ERROR_MORE_DATA = 234;
    const int ERROR_NO_MORE_ITEMS = 259;
    const int ERROR_NO_NET_OR_BAD_PATH = 1203;
    const int ERROR_NO_NETWORK = 1222;
    const int ERROR_SESSION_CREDENTIAL_CONFLICT = 1219;

    const int ERROR_BAD_PROFILE = 1206;
    const int ERROR_CANNOT_OPEN_PROFILE = 1205;
    const int ERROR_DEVICE_IN_USE = 2404;
    const int ERROR_NOT_CONNECTED = 2250;
    const int ERROR_OPEN_FILES = 2401;

    private struct ErrorClass
    {
        public int num;
        public string message;
        public ErrorClass(int num, string message)
        {
            this.num = num;
            this.message = message;
        }
    }

    private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
        new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"), 
        new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"), 
        new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"), 
        new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"), 
        new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"), 
        new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"), 
        new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"), 
        new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"), 
        new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"), 
        new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"), 
        new ErrorClass(ERROR_MORE_DATA, "Error: More Data"), 
        new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"), 
        new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"), 
        new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"), 
        new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"), 
        new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"), 
        new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"), 
        new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"), 
        new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"), 
        new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"), 
        new ErrorClass(ERROR_SESSION_CREDENTIAL_CONFLICT, "Error: Credential Conflict"),
    };

    private static string GetError(int errNum)
    {
        foreach (ErrorClass er in ERROR_LIST)
        {
            if (er.num == errNum) return er.message;
        }
        return "Error: Unknown, " + errNum;
    }
    #endregion

    #endregion
}

You use it simply like

DisconnectFromShare(@"\\server-a\DBFiles", true); //Disconnect in case we are currently connected with our credentials;

ConnectToShare(@"\\server-a\DBFiles", username, password); //Connect with the new credentials

if (!Directory.Exists(@"\\server-a\DBFiles\"))
    Directory.CreateDirectory(@"\\server-a\DBFiles\"+Test);   
File.Copy("C:\Temp\abc.txt", @"\\server-a\DBFiles\");

DisconnectFromShare(@"\\server-a\DBFiles", false); //Disconnect from the server.
Mesencephalon answered 22/7, 2013 at 11:20 Comment(14)
Do I have create [DllImport("Mpr.dll")] file first?Gook
No, Mpr.dll is a part of windows, you use it just like you where going to call User32.dll or Kernal32.dllMesencephalon
Error 3 The type or namespace name 'DllImport' could not be found (are you missing a using directive or an assembly reference?)Gook
You need to include the namespace using System.Runtime.InteropServices; at the top of your file.Mesencephalon
Are you creating the directory at \\server-a\copiedfiles\ or at \\server-a\DBFiles\ , you used both in your example. Also which one did you pass in as the url for the connection. Also did ConnectToShare return a error string?Mesencephalon
the main folder is '\\server-a\DBFiles\Test' but if there is no 'Test' folder then create 'Test' Folder. as I am running this first time so it should create folder. it works first bit that the folder is not exists but then error comes up access denied.Gook
@Gook You need to check the results from ConnectToShare to see if a error happened.Mesencephalon
//Check for errors if (ret == NO_ERROR) return null; else return GetError(ret); It goes to " Else return GetError(ret); " and return number 53 at ret. and then goes to next line to copy a file. and give error there.Gook
You need to check to see if ConnectToShare is returning a string or is returning null, if it is null everything went ok, if you got a string you need to read the string to see what happened.Mesencephalon
ConnectToShare is returning integer. and the loop running twice, I put console writeline statment to return all results. at first loop results are: 5 2250 85 2250 1200 2250 67 2250 1204 2250 1223 2250 1208 2250 487 2250 87 2250 1216 2250 234 2250 259 2250 1203 2250 1222 2250 1206 2250 1205 2250 2404 2250 1208 2250...... and second loop giving this results. 5 53 85 53 1200 53 67 53 1204 53 1223 53 1208 53 487 53 87 53 1216 53 234 53 259 53 1203 53 1222 53 1206 53 1205 53 2404 53 1208 53 2250 53 2401 53 1219 53 after this it gave error access to the path ... is denied.Gook
this is the loop running twice: foreach (ErrorClass er in ERROR_LIST) { if (er.num == errNum) return er.message; Console.WriteLine(er.num); Console.WriteLine(errNum); }Gook
this is the loop running twice: foreach (ErrorClass er in ERROR_LIST) { if (er.num == errNum) return er.message; Console.WriteLine(er.num); Console.WriteLine(errNum); }Gook
this error I am getting after the above error...A first chance exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dllGook
Is it bad practice to use NET USE instead of impersonate? Im using only Windows only and this was way easier to get working....Pest
S
9

You can use impersonation to change the threads user context:

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
    int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
...
LogonUser(userName, domainName, password,
            LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
            out safeTokenHandle);
...
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
            {
                using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
                {

                    // Check the identity.
                    Console.WriteLine("After impersonation: "
                        + WindowsIdentity.GetCurrent().Name);
                    //Do your coping here
                }
            }

MSDN Sample windowsimpersonationcontext

Socman answered 22/7, 2013 at 11:13 Comment(4)
what I have to do here. Didnt understand.Gook
Have you seen the msdn sample?Socman
@Gook You add the first section to your class. The 2nd section is what you use in your function in order to establish impersonation and output safeTokenHandle. The 3rd section follows directly after and uses that token to give you a WindowsIdentity from that token, which is an identity representative of the newly-logged in user. Windows then needs a context for that WindowsIdentity, ran in the form of a WindowsImpersonationContext when .Impersonate() is run on that WindowsIdentity. Where the Console.WriteLine statement is, is where you do your file copying.Ichthyosaur
In order to run this code, though, you'd also need to add private static IntPtr safeTokenHandle = new IntPtr(0); const int LOGON32_LOGON_INTERACTIVE = 2; const int LOGON32_PROVIDER_DEFAULT = 0; at the top of your class, along with variables for the userName, domainName, and password to pass to LogonUser(), like is shown in that 2nd snippet.Ichthyosaur
D
3
NetworkShare.DisconnectFromShare(@"\\server-a\DBFiles", true); //Remove this line
NetworkShare.ConnectToShare(@"\\server-a\DBFiles", "user1", "password1!"); //Connect with the new credentials

File.Copy(@"c:\temp\T1.txt", @"\\server-a\DBFiles\T1.txt");

NetworkShare.DisconnectFromShare(@"\\server-a\DBFiles", false); //Remove this line also

After 02 days search in Google finally the above worked for me. If you use 'NetworkShare.DisconnectFromShare' after the first login you will get an error as 'Access denied'. Then every time you need to restart the server or need to execute 'net use * /del' command to delete the saved credentials in windows.

Demonic answered 30/12, 2015 at 15:38 Comment(1)
Seems, then, like there's an issue with the disconnection routine-emphasize it shouldn't be used - not just in the code comments. I had to read this post a couple of times to figure out what you were saying.Ichthyosaur
Y
1

I have done this file copy from remote server. please find the code.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.Security.Principal;
using System.Runtime.InteropServices;
namespace IMPolicy
{
public partial class ExtractData : System.Web.UI.Page
{
    [DllImport("advapi32.DLL", SetLastError = true)]
    public static extern int LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
    protected void Page_Load(object sender, EventArgs e)
    {            

        AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

        IntPtr token = default(IntPtr);
        if (LogonUser("UserName", "Domain", "Password", 2, 0, ref token) != 0)
        {

            WindowsIdentity identity = new WindowsIdentity(token);
            WindowsImpersonationContext context = identity.Impersonate();

            try
            {                
                File.Copy(@"\\\\10.10.38.25\d$\\Sourav\\Draft Report ITC-LRBD_Online Booking Portal_12082016.pdf", @"d:\\Draft Report ITC-LRBD_Online Booking Portal_12082016.pdf", true);
             }
             finally
             {
                 context.Undo();
             }
        }




    }


  }
}
Yoruba answered 10/7, 2017 at 10:59 Comment(0)
H
0
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;

namespace Files_copy_from_Server
{
    class Program
    {
        static void Main(string[] args)
        {
            NetworkShare.copyfiles();
            Console.ReadLine();
        }
    }
    public static class NetworkShare
    {
        public static  void copyfiles()
        {
            try
            {
                string username = "username";
                string password = "Password";
                DisconnectFromShare(@"\\192.168.11.95\Destination", true); 

//Disconnect in case we are currently connected with our credentials;
                    ConnectToShare(@"\\192.168.11.95\Destination", username, password); //Connect with the new credentials
                    if (!Directory.Exists(@"\\192.168.11.95\Destination\"))
                    Directory.CreateDirectory(@"\\192.168.11.95\Destination\");
                    File.Copy(@"D:\OldBackup\CADCallEnvelopBL.cs", @"\\192.168.11.95\Destination\CADCallEnvelopBL.cs");
                    DisconnectFromShare(@"\\192.168.11.95\Destination\", false); 
 //Disconnect from the server.
                }
                catch (Exception objError)
                {
                Console.Write(objError.Message);
            }
        }
        /// <summary>
        /// Connects to the remote share
        /// </summary>
        /// <returns>Null if successful, otherwise error message.</returns>
        public static string ConnectToShare(string uri, string username, string 
        password)
        {
            //Create netresource and point it at the share
            NETRESOURCE nr = new NETRESOURCE();
            nr.dwType = RESOURCETYPE_DISK;
            nr.lpRemoteName = uri;
        //Create the share
        int ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);

        //Check for errors
        if (ret == NO_ERROR)
            return null;
        else
            return GetError(ret);
    }

    /// <summary>
    /// Remove the share from cache.
    /// </summary>
    /// <returns>Null if successful, otherwise error message.</returns>
    public static string DisconnectFromShare(string uri, bool force)
    {
        //remove the share
        int ret = WNetCancelConnection(uri, force);

        //Check for errors
        if (ret == NO_ERROR)
            return null;
        else
            return GetError(ret);
    }

    #region P/Invoke Stuff
    [DllImport("Mpr.dll")]
    private static extern int WNetUseConnection(
        IntPtr hwndOwner,
        NETRESOURCE lpNetResource,
        string lpPassword,
        string lpUserID,
        int dwFlags,
        string lpAccessName,
        string lpBufferSize,
        string lpResult
        );

    [DllImport("Mpr.dll")]
    private static extern int WNetCancelConnection(
        string lpName,
        bool fForce
        );

    [StructLayout(LayoutKind.Sequential)]
    private class NETRESOURCE
    {
        public int dwScope = 0;
        public int dwType = 0;
        public int dwDisplayType = 0;
        public int dwUsage = 0;
        public string lpLocalName = "";
        public string lpRemoteName = "";
        public string lpComment = "";
        public string lpProvider = "";
    }

    #region Consts
    const int RESOURCETYPE_DISK = 0x00000001;
    const int CONNECT_UPDATE_PROFILE = 0x00000001;
    #endregion

    #region Errors
    const int NO_ERROR = 0;

    const int ERROR_ACCESS_DENIED = 5;
    const int ERROR_ALREADY_ASSIGNED = 85;
    const int ERROR_BAD_DEVICE = 1200;
    const int ERROR_BAD_NET_NAME = 67;
    const int ERROR_BAD_PROVIDER = 1204;
    const int ERROR_CANCELLED = 1223;
    const int ERROR_EXTENDED_ERROR = 1208;
    const int ERROR_INVALID_ADDRESS = 487;
    const int ERROR_INVALID_PARAMETER = 87;
    const int ERROR_INVALID_PASSWORD = 1216;
    const int ERROR_MORE_DATA = 234;
    const int ERROR_NO_MORE_ITEMS = 259;
    const int ERROR_NO_NET_OR_BAD_PATH = 1203;
    const int ERROR_NO_NETWORK = 1222;
    const int ERROR_SESSION_CREDENTIAL_CONFLICT = 1219;

    const int ERROR_BAD_PROFILE = 1206;
    const int ERROR_CANNOT_OPEN_PROFILE = 1205;
    const int ERROR_DEVICE_IN_USE = 2404;
    const int ERROR_NOT_CONNECTED = 2250;
    const int ERROR_OPEN_FILES = 2401;

    private struct ErrorClass
    {
        public int num;
        public string message;
        public ErrorClass(int num, string message)
        {
            this.num = num;
            this.message = message;
        }
    }

    private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
    new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"),
    new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"),
    new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"),
    new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"),
    new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"),
    new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"),
    new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
    new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"),
    new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"),
    new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"),
    new ErrorClass(ERROR_MORE_DATA, "Error: More Data"),
    new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"),
    new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"),
    new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"),
    new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"),
    new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"),
    new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"),
    new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
    new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"),
    new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"),
    new ErrorClass(ERROR_SESSION_CREDENTIAL_CONFLICT, "Error: Credential Conflict"),
};
    private static string GetError(int errNum)
    {
        foreach (ErrorClass er in ERROR_LIST)
        {
            if (er.num == errNum)
            {
                return er.message;                
            }             
        }
        return "Error: Unknown, " + errNum;
    }
    #endregion

    #endregion
}

}

Hailstone answered 26/3, 2021 at 15:47 Comment(1)
Welcome, and thank you for contributing your code. Can you update your answer to include some more explanation of what you're doing, and also highlight what the key parts of your code are that address the specific question? Generally, we try to avoid large dumps of code as answers, as they don't help future readers learn the concepts or apply them to different scenarios.Aventine

© 2022 - 2024 — McMap. All rights reserved.