NET 2.0 ServiceController.GetServices() [英] .Net 2.0 ServiceController.GetServices()

查看:415
本文介绍了NET 2.0 ServiceController.GetServices()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个网站,有Windows身份验证启用它。从网站的页面时,用户必须启动做一些事情与数据库服务的能力。

I've got a website that has windows authentication enable on it. From a page in the website, the users have the ability to start a service that does some stuff with the database.

它正常工作,对我来说,因为我是在服务器上的本地管理员启动服务。不过,我刚刚有了一个用户的测试,他们无法得到服务启动。

It works fine for me to start the service because I'm a local admin on the server. But I just had a user test it and they can't get the service started.

我的问题是:


有谁知道的方式来使用不同的窗口通过名字来取得指定的计算机上的服务列表占比他们目前正在与登录的吗?


我真的不希望添加所有需要启动该服务为Windows组,并将它们全部设置为本地管理我的IIS服务器上的用户.....

I really don't want to add all the users that need to start the service into a windows group and set them all to a local admin on my IIS server.....

下面是一些code我已经得到的:

Here's some of the code I've got:

public static ServiceControllerStatus FindService()
        {
            ServiceControllerStatus status = ServiceControllerStatus.Stopped;

            try
            {
                string machineName = ConfigurationManager.AppSettings["ServiceMachineName"];
                ServiceController[] services = ServiceController.GetServices(machineName);
                string serviceName = ConfigurationManager.AppSettings["ServiceName"].ToLower();

                foreach (ServiceController service in services)
                {
                    if (service.ServiceName.ToLower() == serviceName)
                    {
                        status = service.Status;
                        break;
                    }
                }
            }
            catch(Exception ex)
            {
                status = ServiceControllerStatus.Stopped;
                SaveError(ex, "Utilities - FindService()");
            }

            return status;
        }

我的例外来自try块的第二行。这里的错误:

My exception comes from the second line in the try block. Here's the error:

System.InvalidOperationException:
  无法打开服务控制管理器上
  计算机'server.domain.com'。这个
  操作可能需要其他
  特权。 --->
  System.ComponentModel.Win32Exception:
  访问被拒绝---的内端
  异常堆栈跟踪---在
  System.ServiceProcess.ServiceController.GetDataBaseHandleWithAccess(字符串
  计算机名,的Int32
  serviceControlManaqerAccess)在
  System.ServiceProcess.ServiceController.GetServicesOfType(字符串
  计算机名,的Int32的serviceType)在
  TelemarketingWebSite.Utilities.StartService()

System.InvalidOperationException: Cannot open Service Control Manager on computer 'server.domain.com'. This operation might require other privileges. ---> System.ComponentModel.Win32Exception: Access is denied --- End of inner exception stack trace --- at System.ServiceProcess.ServiceController.GetDataBaseHandleWithAccess(String machineName, Int32 serviceControlManaqerAccess) at System.ServiceProcess.ServiceController.GetServicesOfType(String machineName, Int32 serviceType) at TelemarketingWebSite.Utilities.StartService()

感谢您的帮助/信息

推荐答案

注:这并没有解决列举服务为不同的用户,但由于你在做什么更广泛的描述,我认为这是一个很好的答案。

我认为你可以简化这个了很多,甚至有可能避免安全问题的一部分,如果你直接去到感兴趣的服务。而不是调用GetServices的,试试这个:

I think you can simplify this a lot, and possibly avoid part of the security problem, if you go directly to the service of interest. Instead of calling GetServices, try this:

string machineName = ConfigurationManager.AppSettings["ServiceMachineName"];
string serviceName = ConfigurationManager.AppSettings["ServiceName"];
ServiceController service = new ServiceController( serviceName, machineName );
return service.Status;

此直接连接到感兴趣的服务和绕过枚举/搜索步骤。因此,它不需要调用者有 SC_MANAGER_ENUMERATE_SERVICE 有权在服务控制管理器(SCM),其中远程用户默认不具备。它仍然需要 SC_MANAGER_CONNECT ,而根据应该授予远程认证用户MSDN

This connects directly to the service of interest and bypasses the enumeration/search step. Therefore, it doesn't require the caller to have the SC_MANAGER_ENUMERATE_SERVICE right on the Service Control Manager (SCM), which remote users do not have by default. It does still require SC_MANAGER_CONNECT, but according to MSDN that should be granted to remote authenticated users.

一旦你找到感兴趣的服务,你仍然需要能够停止和启动它,你的远程用户可能没有权利这样做。然而,这是可能的个人服务,这将让您授予远程用户访问停下来,而不需要他们是本地管理员启动服务修改安全描述符(DACL)。这是通过 SetNamedSecurityInfo API函数来完成。您需要授予访问权限是 SERVICE_START SERVICE_STOP 。根据到底哪个群体,这些用户属于,你可能还需要向他们发放 GENERIC_READ 。所有这些权利在MSDN 描述。

Once you have found the service of interest, you'll still need to be able to stop and start it, which your remote users probably don't have rights to do. However, it's possible to modify the security descriptor (DACL) on individual services, which would let you grant your remote users access to stop and start the service without requiring them to be local admins. This is done via the SetNamedSecurityInfo API function. The access rights you need to grant are SERVICE_START and SERVICE_STOP. Depending on exactly which groups these users belong to, you might also need to grant them GENERIC_READ. All of these rights are described in MSDN.

下面是一些C ++ code,将执行此设置,假设感兴趣的用户是远程服务控制器组(你会创造)和服务名称是我的服务名称。请注意,如果你想授予访问知名集团,例如用户(不一定是个好主意),而不是创建一个组,您需要更改 TRUSTEE_IS_GROUP TRUSTEE_IS_WELL_KNOWN_GROUP

Here is some C++ code that would perform this setup, assuming the users of interest are in the "Remote Service Controllers" group (which you would create) and the service name is "my-service-name". Note that if you wanted to grant access to a well-known group such as Users (not necessarily a good idea) rather than a group you created, you need to change TRUSTEE_IS_GROUP to TRUSTEE_IS_WELL_KNOWN_GROUP.

在code有没有错误检查,你会想补充。这可能失败(GET / SetNamedSecurityInfo和SetEntriesInAcl)返回0所有三个功能表示成功。

The code has no error checking, which you would want to add. All three functions that can fail (Get/SetNamedSecurityInfo and SetEntriesInAcl) return 0 to indicate success.

另注:您还可以使用 SC工具设置服务的安全描述符,它可以根据%WINDIR%\\ System32下被发现,但不涉及任何编程。

Another Note: You can also set a service's security descriptor using the SC tool, which can be found under %WINDIR%\System32, but that doesn't involve any programming.

#include "windows.h"
#include "accctrl.h"
#include "aclapi.h"

int main()
{
	char serviceName[] = "my-service-name";
	char userGroup[] = "Remote Service Controllers";

	// retrieve the security info
	PACL pDacl = NULL;
	PSECURITY_DESCRIPTOR pDescriptor = NULL;
	GetNamedSecurityInfo( serviceName, SE_SERVICE,
		DACL_SECURITY_INFORMATION, NULL, NULL,
		&pDacl, NULL, &pDescriptor );

	// add an entry to allow the users to start and stop the service
	EXPLICIT_ACCESS access;
	ZeroMemory( &access, sizeof(access) );
	access.grfAccessMode = GRANT_ACCESS;
	access.grfAccessPermissions = SERVICE_START | SERVICE_STOP;
	access.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
	access.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
	access.Trustee.ptstrName = userGroup;
	PACL pNewDacl;
	SetEntriesInAcl( 1, &access, pDacl, &pNewDacl );

	// write the changes back to the service
	SetNamedSecurityInfo( serviceName, SE_SERVICE,
		DACL_SECURITY_INFORMATION, NULL, NULL,
		pNewDacl, NULL );

	LocalFree( pNewDacl );
	LocalFree( pDescriptor );
}

这也可以从C#使用P / Invoke完成,但是这是一个有点更多的工作。

This could also be done from C# using P/Invoke, but that's a bit more work.

如果您仍然特别希望能够枚举服务这些用户,需要向他们发放了 SC_MANAGER_ENUMERATE_SERVICE 对上SCM。不幸的是,根据MSDN ,供应链管理的安全只能在Windows上修改Server 2003 SP1或更高版本。

If you still specifically want to be able to enumerate services as these users, you need to grant them the SC_MANAGER_ENUMERATE_SERVICE right on the SCM. Unfortunately, according to MSDN, the SCM's security can only be modified on Windows Server 2003 sp1 or later.

这篇关于NET 2.0 ServiceController.GetServices()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆