Impersonation and UNC shares in a windows service

C

Chris

Hello all,
Here is my problem. I have a windows service (C#) that is
supposed to move files from/to the local drive to/from a
UNC share (\\domainserver\share). The service is running
on a Win3k server not connected to a domain, as a local
user. The service impersonates a local user (on
domainserver) that has full permissions to that share. Any
File.Move, File.Copy operations are successfull. Any
Directory.GetFiles fail with "Logon failure: unknown user
name or bad password", stack trace is Exception stack
trace: at System.IO.__Error.WinIOError(Int32 errorCode,
String str) at
System.IO.Directory.InternalGetFileDirectoryNames(String
fullPath, String userPath, Boolean file) at
System.IO.Directory.InternalGetFiles(String path, String
userPath, String searchPattern) at
System.IO.Directory.GetFiles(String path, String
searchPattern). The call succeeds if I run the service
under a local account with the same user name/pwd or if
the server is connected to the domain and the service runs
as any domain account.
The impersonation code is similar with the samples from
MSDN (sorry about the formatting):
public static void ImpersonateUser(string domainName,
string userName, string password)
{
IntPtr tokenHandle = new IntPtr(0);
IntPtr dupeTokenHandle = new IntPtr
(0);
try
{
// Get the user token for
the specified user, domain, and password using the
// unmanaged LogonUser
method.

const int
SecurityImpersonation = 2;

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

// Call LogonUser to
obtain a handle to an access token.
bool returnValue =
LogonUser(userName, domainName, password,
(int)
LogonType.LOGON32_LOGON_NEW_CREDENTIALS, (int)

LogonProvider.LOGON32_PROVIDER_DEFAULT, ref
tokenHandle);

if (false == returnValue)
{
int ret =
Marshal.GetLastWin32Error();
throw new
System.ComponentModel.Win32Exception(ret, GetErrorMessage
(ret));
}

//Duplicate the token
bool retVal =
DuplicateToken(tokenHandle, SecurityImpersonation, ref
dupeTokenHandle);

if (false == retVal)
{
CloseHandle
(tokenHandle);
throw new
ApplicationException("Exception thrown in trying to
duplicate token.");
}

// The token that is
passed to the following constructor must
// be a primary token in
order to use it for impersonation.
WindowsIdentity newId =
new WindowsIdentity(dupeTokenHandle);

WindowsImpersonationContext impersonatedUser =
newId.Impersonate();

try
{
do stuff;
}
catch {}

// Stop impersonating the
user.
impersonatedUser.Undo();

// Free the tokens.
if (tokenHandle !=
IntPtr.Zero)
CloseHandle
(tokenHandle);
if (dupeTokenHandle !=
IntPtr.Zero)
CloseHandle
(dupeTokenHandle);
}
catch(Exception ex)
{
throw ex;
}
}
}

Thanks a lot for any help or ideas,
Chris
 
W

Willy Denoyette [MVP]

This works for me.

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using System.Reflection;

namespace ImpersonateTest
{
class Class1
{
[DllImport("advapi32.dll")]
public static extern int LogonUser(String lpszUsername, String lpszDomain,
String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

[DllImport("kernel32.dll")]
public extern static bool CloseHandle(IntPtr hToken);

static void Main(s)
{
Class1 c = new Class1();
if(c.Impersonate("someuserOnRemoteSrv", "RemoteSrv", "hisPwd"))
{
string[] dirs = Directory.GetFiles(@"\\RemoteSrv\xxxx", "*");
foreach (string dir in dirs)
Console.WriteLine(dir);
c.impersonationContext.Undo();
}
else
Console.WriteLine("Impersonation failed");
}

public bool Impersonate(string userName, string domain, string password)
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
// request default security provider a logon token with
LOGON32_LOGON_NEW_CREDENTIALS,
// token returned is impersonation token, no need to duplicate
if(LogonUser(userName, domain, password, 9, 0, ref token) != 0)
{
tempWindowsIdentity = new WindowsIdentity(token);
impersonationContext = tempWindowsIdentity.Impersonate();
// close impersonation token, no longer needed
CloseHandle(token);
if (impersonationContext != null)
return true;
}
return false; // Failed to impersonate.
}

WindowsImpersonationContext impersonationContext;
}
}

Willy.
 
C

Chris

Thanks for the quick reply Willy. The only difference I
see is that you're not duplicating the token. I'll give it
a try tomorrow and let you know how it works out.

Chris
 
W

Willy Denoyette [MVP]

Chris, It doesn't really mather, the DuplicateToken is only needed when the
token obtained when calling Logon user is not an impersonation token.
It works also when impersonating using the token obtained by DuplicateToken.

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top