Search code examples
c#network-programmingdirectoryimpersonation

C# Directory.exist always return false on the local network


I'm trying to check wether a directory exist on not or a local network. After some research on stackoverflow and MSDN, I develop my code by using impersonate method. The problem is it's not working very well, The Directory.exists() method always return False Here you have my code (it's nearly the same as the one from MSDN):

public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeTokenHandle()
            : base(true)
        {
        }

        [DllImport("kernel32.dll")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        protected override bool ReleaseHandle()
        {
            return CloseHandle(handle);
        }
    }

 class Environment
    {
        [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);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;

        private void m_SendAlertes()
        {
                SafeTokenHandle safeTokenHandle;
                string v_pathToDir = "\\192.168.1.199\Clients SiteInternet";

                if (!LogonUser("RKalculateur", "SERVEUR2", 
                                "riskedge", LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle))
                {
                    int ret = Marshal.GetLastWin32Error();
                    throw new System.ComponentModel.Win32Exception(ret);
                }
                using (safeTokenHandle)
                {
                    using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
                    {
                        using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
                        {
                            if (Directory.Exists(@v_pathToDir))
                            {
                               // Proceed code here
                            }
                        }
                    }
                }
        }
    }

Here you have a picture of the rights for this directory : enter image description here


Solution

  • It's probably an issue connected to user permissions.

    From MSDN:

    If you do not have at a minimum read-only permission to the directory, the Exists method will return false.

    If you're using local account and not domain account, using Directory.Exists() method is problematic.

    I had similar problem in the past: I had to check if a net share existed in my network and there was no domain. Your way didn't work for me. In the end, I gave up on Directory.Exists() method and ended up using NET USE command ( http://www.cezeo.com/tips-and-tricks/net-use-command/ )

    bool exists = false;
    string output = "";
    string error = "";
    
    System.Diagnostics.Process process = new System.Diagnostics.Process();
    process = new System.Diagnostics.Process();
                ExecuteShellCommand(process, "NET USE", "\""+ @path + "\" "+
                   this.password+ " /USER:"+machinename+"\\"+username + " /PERSISTENT:NO",
                   ref output, ref error);
    Console.WriteLine("\r\n\t__________________________"+
                    "\r\n\tOutput:" + output.Trim().Replace("\r", " ") +
                    "\r\n\tError: " + error.Trim().Replace("\r"," "));
    
                if (output.Length>0 && error.Length==0)
                {
                    exists = true;
                }
    
                process = new System.Diagnostics.Process();
                ExecuteShellCommand(process, "NET USE", " /DELETE " + @path,
                    ref output, ref error);
    

    ....

    public void ExecuteShellCommand(System.Diagnostics.Process process, string fileToExecute,
            string command, ref string output, ref string error)
        {
            try
            {
                string CMD = string.Format(System.Globalization.CultureInfo.InvariantCulture, @"{0}\cmd.exe", new object[] { Environment.SystemDirectory });
                string args = string.Format(System.Globalization.CultureInfo.InvariantCulture, "/C {0}", new object[] { fileToExecute });
                if (command != null && command.Length > 0)
                {
                    args += string.Format(System.Globalization.CultureInfo.InvariantCulture, " {0}", new object[] { command, System.Globalization.CultureInfo.InvariantCulture });
                }
    
                System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(CMD, args);
    
                startInfo.CreateNoWindow = true;
                startInfo.UseShellExecute = false;
                startInfo.RedirectStandardOutput = true;
                startInfo.RedirectStandardInput = true;
                startInfo.RedirectStandardError = true;
    
                process.StartInfo = startInfo;
    
                process.Start();
    
                // timeout
    process.WaitForExit(10 * 1000);
    output = process.StandardOutput.ReadToEnd();
                 error = process.StandardError.ReadToEnd();
            }
            catch (Win32Exception e32)
            {
                Console.WriteLine("Win32 Exception caught in process: {0}", e32.ToString());
            }
            catch (Exception e
            {
                Console.WriteLine("Exception caught in process: {0}", e.ToString());
            }
            finally
            {
                // close process and do cleanup
                process.Close();
                process.Dispose();
                process = null;
            }
        }
    

    I know it's a hack but it worked for me and it's a possibility. (Although you may need to set up a proper net share)