I've read tons of articles about this error.. also trying to set the folder's permission to the lowest:
But I still getting the error: Access to the path '\servername\shareFolder$\folderNameWeWantToCreate' is denied.
I am trying to check whether a directory exists and try to create a directory if not using the below code:
string Folderpath = #"\\servername\shareFolder$\folderNameWeWantToCreate";
if (!Directory.Exists(FolderPath))
Directory.CreateDirectory(FolderPath);
The above code works well on local, but the error comes out when put on to the server.
Is there anything I did wrong??
You have to impersonate identity for user
http://technet.microsoft.com/en-us/library/cc730708%28v=ws.10%29.aspx
There are two possible solutions:
Application Pool Identity
You need to create a new Application Pool in IIS that runs as the LocalSystem user and change your application to run on that AppPool. You need a high privilege user to do stuff on the local HD anyway and this'll save you a lot of permission slinging. In the future if you want to harden security you can always go back to a low privilege AppPool and just grant it permissions wherever it needs them.
Remote User Impersonation
If the above doesn't work, this is your recourse. It seems tricky but the code I'm running works perfectly on ASP.NET MVC 5 / .NET 4.5.1 so it should run fine on older versions too. Here's the code:
Helper classes:
public class ImpersonationHelper
{
[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);
public const int LOGON32_PROVIDER_DEFAULT = 0;
public const int LOGON32_PROVIDER_WINNT50 = 3;
public const int LOGON32_PROVIDER_WINNT40 = 2;
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_NEW_CREDENTIALS = 9;
public static SafeTokenHandle GetSafeTokenHandle(string userName, string password, string domain)
{
SafeTokenHandle safeTokenHandle;
bool returnValue = LogonUser(userName, domain, password,
LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50,
out safeTokenHandle);
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(ret);
}
return safeTokenHandle;
}
}
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);
}
}
Main code:
var remoteUser = ConfigurationManager.AppSettings["RemoteUser"];
var remotePassword = ConfigurationManager.AppSettings["RemotePassword"];
var remoteDomain = ConfigurationManager.AppSettings["RemoteDomain"];
var safeTokenHandle = ImpersonationHelper.GetSafeTokenHandle(remoteUser, remotePassword, remoteDomain);
using (safeTokenHandle)
{
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
{
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
// do stuff here the same as you would locally
}
}
}
Related
I have an application that runs with the system user. I need that some code in the app runs on user context (with the user itself). For example i need to use the webclient in user context because that way my firewall recognize the username, but later i need to run some other code ex. Running a exe in system context (with system user) because i need the privileges.
Is there a way to do this?.
Thanks!!!
I have used this code to impersonate certain operations
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;
using NLog;
namespace Core.Impersonation
{
public class ImpersonatedUser : IDisposable
{
private static Logger logger = LogManager.GetCurrentClassLogger();
IntPtr userHandle;
WindowsImpersonationContext impersonationContext;
public ImpersonatedUser(string user, string domain, string password)
{
logger.Debug("Impersonating user: " + domain + #"\" + user);
userHandle = IntPtr.Zero;
bool loggedOn = LogonUser(
user,
domain,
password,
LogonType.Interactive,
LogonProvider.Default,
out userHandle);
if (!loggedOn)
throw new Win32Exception(Marshal.GetLastWin32Error());
// Begin impersonating the user
impersonationContext = WindowsIdentity.Impersonate(userHandle);
}
public void Dispose()
{
if (userHandle != IntPtr.Zero)
{
CloseHandle(userHandle);
userHandle = IntPtr.Zero;
impersonationContext.Undo();
logger.Debug("Finished Impersonating user");
}
}
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool LogonUser(
string lpszUsername,
string lpszDomain,
string lpszPassword,
LogonType dwLogonType,
LogonProvider dwLogonProvider,
out IntPtr phToken
);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hHandle);
enum LogonType : int
{
Interactive = 2,
Network = 3,
Batch = 4,
Service = 5,
NetworkCleartext = 8,
NewCredentials = 9,
}
enum LogonProvider : int
{
Default = 0,
}
}
}
and then usage:
using (var i = new ImpersonatedUser("someLogin", "someDomain", "thePassword"))
{
var u = System.Environment.UserName;
}
I want users to be able to change the display name of an existing Windows service using our configuration tool. In code, given an instance of the corresponding ServiceController object, setting its DisplayName property seems to have effect. Tried calling Refresh, which seemed to have no effect. The MSDN doc is a little unclear on what Refresh does - does it reread the current service settings or does it write my changes to the service? Code is simple:
ServiceController sc = GetServiceController(CurrentInterfaceData.ServiceName);
sc.DisplayName = "MyService";
sc.Refresh();
Use WMI. For that you have to add a reference to System.Management assembly. Here is excerpt of a working code that I had used for a generic installer:
class Program
{
static void Main(string[] args)
{
UpdateService("ipsecd");
}
private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
private const int LOGON32_PROVIDER_WINNT50 = 3;
private const int SERVICE_ALL_ACCESS = 0xF01FF;
private const int SC_MANAGER_ALL_ACCESS = 0xF003F;
private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF;
private const uint SERVICE_WIN32_OWN_PROCESS = 0x00000010;
private const uint SERVICE_INTERACTIVE_PROCESS = 0x00000100;
// Win32 function to connect to remote machine
[DllImport("advapi32.dll", SetLastError = true)]
private static extern Boolean LogonUser(string lpUsername, string lpDomain, string lpPassword, int dwLogonType,
int dwLogonProvider, out IntPtr phToken);
// Win32 function to connect to impersonate user
[DllImport("advapi32.dll", SetLastError = true)]
static extern int ImpersonateLoggedOnUser(IntPtr hToken);
// Win32 function to open the service control manager
[DllImport("advapi32.dll")]
private static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, int dwDesiredAccess);
// Win32 function to open a service instance
[DllImport("advapi32.dll")]
private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, int dwDesiredAccess);
// Win32 function to change the service config
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern Boolean ChangeServiceConfig(
IntPtr hService,
UInt32 nServiceType,
UInt32 nStartType,
UInt32 nErrorControl,
String lpBinaryPathName,
String lpLoadOrderGroup,
IntPtr lpdwTagId,
[In] char[] lpDependencies,
String lpServiceStartName,
String lpPassword,
String lpDisplayName);
public static void UpdateService(string serviceName)
{
ManagementScope scope = null;
ObjectQuery filter = new ObjectQuery(string.Format("SELECT * FROM Win32_Service WHERE Name = '{0}'", serviceName));
ManagementObjectSearcher query = new ManagementObjectSearcher(scope, filter);
try
{
ManagementObjectCollection services = query.Get();
// No match = failed condition
if (services.Count == 0)
return;
foreach (ManagementObject service in services)
{
SetServiceDisplayName(serviceName, "new disp name");
service.Dispose();
}
}
catch (Exception ex)
{
//Could not set property
}
}
private static void SetServiceDisplayName(string name, string dispName)
{
IntPtr svcHndl = OpenService("", "", name);
// Call the ChangeServiceFailureActions() abstraction of ChangeServiceConfig2()
bool rslt = ChangeServiceConfig(svcHndl, SERVICE_NO_CHANGE,
SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, null, null, IntPtr.Zero, null, null, null, dispName);
}
private static IntPtr OpenService(string userName, string password, string serviceName)
{
IntPtr scmHndl = IntPtr.Zero;
IntPtr svcHndl = IntPtr.Zero;
// Open the service control manager
scmHndl = OpenSCManager("", null, SC_MANAGER_ALL_ACCESS);
if (scmHndl.ToInt32() <= 0)
return IntPtr.Zero;
// Open the service
svcHndl = OpenService(scmHndl, serviceName, SERVICE_ALL_ACCESS);
if (svcHndl.ToInt32() <= 0)
return IntPtr.Zero;
return svcHndl;
}
}
Try it. It should work.
I believe the name of the Windows Service is set when the service is installed. I don't think that changing it later will have any effect.
I want to read files from a folder that exists on the network.
When I try to access this folder manually (from run command giving a path like \\ABCServer\Documents ) it ask me for credentials (username and password). After giving the correct credentials I am able to access/read files.
When I try to read the same files from C# code in ASP.NET it gives me an error:
Login Failure: unkown username or bad password
How can I pass credentials via C# code during reading file?
Below is a part of the code that I am using:
Stream s = File.OpenRead(filePath);
byte[] buffer = new byte[s.Length];
try
{
s.Read(buffer, 0, (Int32)s.Length);
}
finally
{
s.Close();
}
Note:
The code works fine
I'm using ASP.NET 4.0 with C#
IIS version is 7.5
This is from http://support.microsoft.com/kb/306158
public const int LOGON32_LOGON_INTERACTIVE=2;
public const int LOGON32_PROVIDER_DEFAULT=0;
WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
private bool impersonateValidUser(String userName, String domain, String password) {
WindowsIdentity tempWindowsIdentity;
IntPtr token=IntPtr.Zero;
IntPtr tokenDuplicate=IntPtr.Zero;
if(RevertToSelf()) {
if(LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token)!=0) {
if(DuplicateToken(token, 2, ref tokenDuplicate)!=0) {
tempWindowsIdentity=new WindowsIdentity(tokenDuplicate);
impersonationContext=tempWindowsIdentity.Impersonate();
if(impersonationContext!=null) {
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if(token!=IntPtr.Zero)
CloseHandle(token);
if(tokenDuplicate!=IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
private void undoImpersonation() {
impersonationContext.Undo();
}
You can do this using impersonation. Here is a question and answers of how it is done.
My objective is to copy a folder from my system to a remote computer in c#.
I searched everywhere and found some information on how to do that. I am calling the LogonUser function with the domain, username and password, but it it fails and returns 0.
below is my piece of code. Can you please help me figure out the problem?
class Program
{
#region Assembly Functions
[DllImport("advapi32.dll")]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword,
int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr handle);
#endregion
static void Main(string[] args)
{
SafeTokenHandle safeTokenHandle;
WindowsImpersonationContext impersonatedUser = null;
WindowsIdentity newId;
IntPtr tokenHandle;
IntPtr userHandle = IntPtr.Zero;
tokenHandle = IntPtr.Zero;
Console.WriteLine("Enter your domain.");
string domain = Console.ReadLine();
Console.WriteLine("Enter you user name.");
string uname = Console.ReadLine();
Console.WriteLine("Enter your password (Caution, password won't be hidden).");
string password = Console.ReadLine();
const int LOGON32_PROVIDER_DEFAULT = 0;
//This parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;
bool logon = LogonUser(uname, domain, password,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);
if (false == logon)
{
int ret = Marshal.GetLastWin32Error();
Console.WriteLine("LogonUser failed with error code : {0}", ret);
throw new System.ComponentModel.Win32Exception(ret);
}
if (logon)
{
newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle());
using (impersonatedUser = newId.Impersonate())
{
// Check the identity.
Console.WriteLine("After impersonation: "
+ WindowsIdentity.GetCurrent().Name);
}
File.Copy(#"c:\result.xml", #"C:\result.xml", true);
}
//Undo impersonation
if (impersonatedUser != null)
{
impersonatedUser.Undo();
}
if (tokenHandle != IntPtr.Zero)
{
CloseHandle(tokenHandle);
}
}
}
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);
}
}
Why not use "Windows API Code Pack 1.1" which shows (among other things) how to use the shell to do e.g. drag and drop - which is what you essentially try to do.
If using the Shell, you don't have to think about how to logon and 1000 other things needed to support various situations.
Download the "Windows API Code Pack 1.1" package and look for DragAndDropWindow sample or some of the other samples.
I'm getting the following exception when going through some legacy impersonation logic:
Unable to find an entry point named 'LogonUser' in DLL 'advapi32.dll'
I understand that the error means that my app can't find the LogonUser method in the advapi32.dll.
The code looks something like this:
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
if(LogonUser(_username, _domainname, _password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _tokenHandle))
{
//do stuff...
}
Has anyone had a similar error - any suggestions on how to fix it or why it is happening? Is there a better way to do this besides using the advapi32.dll (its a .net 3.5 solution but there are lots of legacy classes)?
Maybe it has something to do with the "ExactSpelling = true"
This seems to work:
public enum LogonType : int
{
Interactive = 2,
Network = 3,
Batch = 4,
Service = 5,
Unlock = 7,
NetworkCleartText = 8,
NewCredentials = 9,
}
public enum LogonProvider : int
{
Default = 0,
}
public class Impersonation : IDisposable
{
#region Dll Imports
[DllImport("kernel32.dll")]
private static extern Boolean CloseHandle(IntPtr hObject);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool LogonUser(string username, string domain,
string password, LogonType logonType,
LogonProvider logonProvider,
out IntPtr userToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool DuplicateToken(IntPtr token, int impersonationLevel,
ref IntPtr duplication);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool ImpersonateLoggedOnUser(IntPtr userToken);
#endregion
#region Private members
private bool _disposed;
private WindowsImpersonationContext _impersonationContext;
#endregion
#region Constructors
public Impersonation(String username, String domain, String password)
{
IntPtr userToken = IntPtr.Zero;
IntPtr userTokenDuplication = IntPtr.Zero;
// Logon with user and get token.
bool loggedOn = LogonUser(username, domain, password,
LogonType.Interactive, LogonProvider.Default,
out userToken);
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 Exception("Could not copy token");
}
}
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
{
throw new Exception("Login failed");
}
}
~Impersonation()
{
Dispose(false);
}
#endregion
#region Public methods
public void Revert()
{
if (_impersonationContext != null)
{
// Revert to previous user.
_impersonationContext.Undo();
_impersonationContext = null;
}
}
#endregion
#region IDisposable implementation.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
Revert();
_disposed = true;
}
}
#endregion
}
Have you tried using the version of LogonUser's signature provided on pinvoke.net?