views:

1853

answers:

4

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.

A: 

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.

ChrisW
I've got down the permissions path a million times.I was hoping this could be a hacky workaround because I can't solve the permissions issue, but alas I'm back to square 1.
Ryan Smith
A: 

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.

JaredPar
Downvoting a correct answer without a comment is weak.
JaredPar
+2  A: 

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();
AJ
+1  A: 

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?

Michael Blackburn