Impersonation in Windows Service
I have a windows service that grabs a dataset via a SQL connection string from another server. I need to impersonate a specific user account that has access to this SQL Server database. Working with the code works if I create it as a console application, but the Windows service messes things up.
When created as a Windows service, regardless of impersonation, the service tries to connect and authenticate using the computer account (which is incorrect) as stated in the error:
Unable to open database \ "DATABASE \" requested by login. Login failed. Login to user domain DOMAIN \ MACHINENAME failed.
With this piece of code, I am using the impersonator class:
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public DataSet GetDataSetSQL(string pSQL)
{
DataSet ds = null;
DbDataAdapter adapter = null;
try
{
using (impers = new Impersonator(impers_uname, impers_domain, impers_password))
{
/// Create connection
using (DbConnection conn = this.factory.CreateConnection())
{
conn.ConnectionString = this.connectionString;
/// Create Command
using (DbCommand cmd = conn.CreateCommand())
{
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = pSQL;
adapter = this.factory.CreateDataAdapter();
adapter.SelectCommand = cmd;
ds = new DataSet();
adapter.Fill(ds);
}
}
}
}
finally
{
if (adapter != null) adapter = null;
}
return ds;
}
This is where I get the token:
if (LogonUser(
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();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
I could just run a Windows service under a user account, but I want this extra level of granularity as well as portability.
Anyone have any ideas how to differentiate impersonation between Windows applications and services?
Edit
Calling the enum and logonuser function
public enum LogonType
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK = 3,
LOGON32_LOGON_BATCH = 4,
LOGON32_LOGON_SERVICE = 5,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT = 8, // Win2K or higher
LOGON32_LOGON_NEW_CREDENTIALS = 9 // Win2K or higher
};
public enum LogonProvider
{
LOGON32_PROVIDER_DEFAULT = 0,
LOGON32_PROVIDER_WINNT35 = 1,
LOGON32_PROVIDER_WINNT40 = 2,
LOGON32_PROVIDER_WINNT50 = 3
};
if (LogonUser(
userName,
domain,
password,
(int)LogonType.LOGON32_LOGON_NEW_CREDENTIALS,
(int)LogonProvider.LOGON32_PROVIDER_WINNT50,
ref token) != 0)
source to share
Given the 4th parameter to the LogonUser function , you are using LOGON32_LOGON_INTERACTIVE.
This login type is intended for users who will be using the computer interactively, such as a user who logs on to a terminal server, a remote shell, or similar process. but Windows service is not in this category, so I have to use LOGON32_LOGON_SERVICE instead.
source to share