Starting a service in ASP.NET/C# with the right pe

2020-05-03 13:27发布

问题:

on my website (written in ASP.NET/C#) I want the moderaters to be able to start a certain service. The code I have for this is:

    ServiceController svcController = new ServiceController("InvidualFileConversion");

    if (svcController != null)
    {
        try
        {
            svcController.Stop();
            svcController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10));
            svcController.Start();
        }
        catch (Exception ex)
        {
            // error
        }
    }

Now when I run this I get the error "Cannot open InvidualFileConversion service on computer", with the additional message: "Acces is denied".

I know this is a problem with permissions, but how do I give myself the proper permissions? Don't come with the answer where I should write: , cause I have tried it and it didn't work. Also I think that is not really the best way to set this up for the whole website when I just need it for these few lines of code.

EDIT: I've added this in my code and it still doesn't work, I get the same exception at the same place. Now it looks like this:

protected void ConvertLink_OnClick(object sender, EventArgs e)
{
    //convert();
    try
    {
        //--need to impersonate with the user having appropriate rights to start the service
        Impersonate objImpersonate = new Impersonate(domainName, userName, userPassword);
        if (objImpersonate.impersonateValidUser())
        {
            //--write code to start/stop the window service
            startWindowsService();
            objImpersonate.undoImpersonation();
        }
    }
    catch (Exception Ex)
    { Response.Write(Ex.Message + Ex.InnerException.Message); }
}

private void startWindowsService()
{
    ServiceController svcController = new ServiceController("InvidualFileConversion");

    if (svcController != null)
    {
        try
        {
            svcController.Stop();
            svcController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10));
            svcController.Start();
        }
        catch (Exception ex)
        {
            // error
        }
    }
}

I have a Impersonate class that looks like this:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Security.Principal;
using System.Runtime.InteropServices;

/// <summary>
/// Summary description for Impersonate
/// </summary>
public class Impersonate
{

#region "Class Members"
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
#endregion

#region "Class Properties"
public string domainName { get; set; }
public string userName { get; set; }
public string userPassword { get; set; }
#endregion

public Impersonate()
{
    //
    // TODO: Add constructor logic here
    //
}
public Impersonate(string domainName, string userName, string userPassword)
{
    this.domainName = domainName;
    this.userName = userName;
    this.userPassword = userPassword;
}

#region "Impersonation Code"
[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);
public bool impersonateValidUser()
{
    WindowsIdentity tempWindowsIdentity;
    IntPtr token = IntPtr.Zero;
    IntPtr tokenDuplicate = IntPtr.Zero;

    if (RevertToSelf())
    {
        if (LogonUserA(this.userName, this.domainName, this.userPassword, 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;
}

public void undoImpersonation()
{
    impersonationContext.Undo();
}
#endregion
}

So the validation thing works but doesn't solve my problem.. I guess there is still the problem with the permissions.. What do I do to change this?

EDIT 2: The next steps I took involve this:

  1. Creating a app pool where the identity is set to a user (which is member of an administrator group).
  2. Set the service "log on" to the same user.
  3. After running the web app again, it still fails..

However If I put in the Administrator account as credentials in the code, it works.. (Even though I did not use the Administrator in the App Pool and on the service...)

In other words, I can get what I want with the Administrator account, but not with an account I created myself and has the admin rights. I still want to make this work with a user I made myself as I think it is not so safe to put your Administrator credentials available.

On a sidenote, on the server which I work on I have an account that has administrator privileges but is not the 'Administrator'-account.

EDIT 3: This is getting weird. I seems to work now BUT: - without the Impersonation method (it did not work). - I just did what Rob said. I have my own application pool with a user I defined. The windows service has that user specified as well. (The user received Log On As Service right) - With this, it seems to work. - But if debug through my website I still get acces denied. But if just acces my website through the browser and its ip I can start the service.

To sum it up: - Impersonation method doesn't work. - Just using a self created app pool with the currect user works if the service has the user also specified. But it doesn't work in debug mode (still Acces Denied there).

This post is getting to big and I wonder if any still really reads it.. But maybe still someone can provide me with any details? I'm afraid it will fail again somewhere in the future..

Any comment will be appreciated! Floris

回答1:

You have to make sure that your web site is running under a user who have enough right to start the service. Make sure also that the anonymous authentication is disabled on IIS A good way could be to create a user who has rights for starting service on the server web then create an application pool that runs under that user.then you have to make your web site use that application pool. Using this approach all the web site will run under the user you have just create. If you want be more granular you can still create the user that have the rights for starting the service but instead of use it for the application pool you can make only the page that needs to start the service run under that user using the impersonation. You can use the imporsonation feature only for this method!

for more details have a look at the links below:

http://forums.asp.net/t/1137962.aspx/1

http://support.microsoft.com/kb/306158