Abyssul
Abyssul

Reputation: 65

Impersonation in Windows Service

I have a windows service that grabs a data set via SQL connection string from a different server. I need to impersonate a specific user account that has access to this SQL Server database. The code works find if I build it as a console application, but a windows service messes things up.

When building as a windows service, no matter the impersonation, the service tries to connect and authenticate using the machine account (which is wrong) as designated by the error:

Cannot open database \"DATABASE\" requested by the login. The login failed. Login failed for user 'DOMAIN\MACHINENAME'.

With this snippet of code I use 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;
    }

Here 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 the windows service under the user account, but I want to have that extra level of granularity and also portability.

Anyone have any ideas how impersonation is different between applications and windows services?

Edit:

New enums and logonuser function call

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)

Upvotes: 3

Views: 2374

Answers (1)

Matt
Matt

Reputation: 6050

Regards to the 4th parameter the function LogonUser, you're using LOGON32_LOGON_INTERACTIVE.

This logon type is intended for users who will be interactively using the computer, such as a user being logged on by a terminal server, remote shell, or similar process. but Windows service is not in this category, so I thing you should use LOGON32_LOGON_SERVICE instead.

Upvotes: 1

Related Questions