Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File.Exists returning false from a network share

I've been working on a ASP.NET project that is going to save uploaded files to a network share. I figured I could just use a virtual directory and be fine, but I have been struggling with permissions for Directory.CreateDirectory.

I was able to upload files so I decided to change my code to place everything in a single directory, however this requires me to make use of File.Exists to avoid overwriting duplicates.

Now that I have all my code updated, I have discovered that no matter what I do, File.Exists always returns false (The file definitely exists) when I test against the network share.

Any ideas? I'm coming to the very end of my rope with network shares.

like image 760
Ryan Smith Avatar asked Dec 30 '08 19:12

Ryan Smith


4 Answers

File.Exist doesn't actually check for existance of a file. It instead checks for Existance of files that you have some measure of access to. If you know the file exists, the likely problem is that you don't have access to it.

like image 139
JaredPar Avatar answered Oct 19 '22 20:10

JaredPar


I just recently worked on a very similar project where I am saving files to a network share. The two computers are on the same subnet, but are not controlled by domain controller, so each computer has it's own users.

I created a user with the same username and password on both computers. Then I created a network share and set the folder/share permissions to allow read-write for the user.

I then created the following class to manage the impersonation:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
using System.Text;

namespace MyProject.Business.Web
{
    public class SecurityManager
    {
        #region DLL Imports
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
        #endregion

        public string Domain { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }

        private WindowsImpersonationContext m_CurrentImpersonationContext;

        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
        public void StartImpersonation()
        {
            const int LOGON32_PROVIDER_DEFAULT = 0;
            const int LOGON32_LOGON_INTERACTIVE = 2;

            IntPtr tokenHandle = IntPtr.Zero;
            IntPtr dupeTokenHandle = IntPtr.Zero;

            // obtain a handle to an access token
            bool wasLogonSuccessful = LogonUser(UserName, Domain, Password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

            if (!wasLogonSuccessful)
                throw new Exception(String.Format("Logon failed with error number {0}", Marshal.GetLastWin32Error()));

            // use the token handle to impersonate the user
            WindowsIdentity newId = new WindowsIdentity(tokenHandle);
            m_CurrentImpersonationContext = newId.Impersonate();

            // free the tokens
            if (tokenHandle != IntPtr.Zero)
                CloseHandle(tokenHandle);
        }
        public void EndImpersonation()
        {
            m_CurrentImpersonationContext.Undo();
        }
    }
}

Then in the ASP.NET page I did the following:

SecurityManager sm = new SecurityManager();
sm.UserName = ConfigurationManager.AppSettings["UserFileShareUsername"];
sm.Password = ConfigurationManager.AppSettings["UserFileSharePassword"];
sm.StartImpersonation();

if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);

File.Move(sourcePath, destinationPath);

sm.EndImpersonation();
like image 23
Abram Simon Avatar answered Oct 19 '22 19:10

Abram Simon


Perhaps your code which is running (i.e. ASP.NET server code) is running as a user (e.g. the IIS user) which doesn't have permission to access that network share.

I think that IIS isn't supposed to be run as a highly-priviledged user, which by default has permission to view shares on other machines.

like image 2
ChrisW Avatar answered Oct 19 '22 19:10

ChrisW


I used much the same code, but had my class implement the IDisposable interface, and added the Undo() to the Dispose() method. This code works fine, if you're the only developer using it and you'll always do things the right way, right?

like image 2
Michael Blackburn Avatar answered Oct 19 '22 20:10

Michael Blackburn