.Net 2.0 ServiceController.GetServices()
我有一个启用了 Windows 身份验证的网站。 从网站的页面中,用户可以启动一项对数据库执行某些操作的服务。
启动该服务对我来说效果很好,因为我是服务器上的本地管理员。 但我刚刚让一个用户测试了它,但他们无法启动该服务。
我的问题是:
有谁知道如何使用与当前登录帐户不同的 Windows 帐户按名称获取指定计算机上的服务列表?
我真的不想将需要启动服务的所有用户添加到 Windows 组中,并将它们全部设置为我的 IIS 服务器上的本地管理员.....
这是我得到的一些代码:
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 块。 这是错误:
系统.InvalidOperationException: 无法打开服务控制管理器 计算机“server.domain.com”。 这 操作可能需要其他 特权。 ---> System.ComponentModel.Win32Exception: 访问被拒绝 --- 内部结束 异常堆栈跟踪 --- at System.ServiceProcess.ServiceController.GetDataBaseHandleWithAccess(字符串 机器名称,Int32 服务控制管理器访问)位于 System.ServiceProcess.ServiceController.GetServicesOfType(字符串 机器名称,Int32 服务类型)位于 电话营销WebSite.Utilities.StartService()
感谢您的帮助/信息
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.
My question is:
Does anyone know of a way to get a list of services on a specified computer by name using a different windows account than the one they are currently logged in with?
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.....
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;
}
My exception comes from the second line in the try block. Here's the error:
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()
Thanks for the help/info
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
注意:这并不涉及以不同用户身份枚举服务,但考虑到您正在做的事情的更广泛描述,我认为这是一个很好的答案。
我认为您可以简化很多,并且如果您直接访问感兴趣的服务,可能会避免部分安全问题。 不要调用 GetServices,而是尝试以下操作:
这会直接连接到感兴趣的服务并绕过枚举/搜索步骤。 因此,它不需要调用者拥有服务控制管理器 (SCM) 上的
SC_MANAGER_ENUMERATE_SERVICE
权限,而远程用户默认情况下没有该权限。 它仍然需要SC_MANAGER_CONNECT
,但根据 MSDN 应授予远程经过身份验证的用户。一旦找到感兴趣的服务,您仍然需要能够停止和启动它,而您的远程用户可能无权这样做。 但是,可以修改单个服务的安全描述符 (DACL),这将允许您授予远程用户停止和启动服务的访问权限,而无需他们是本地管理员。 这是通过 SetNamedSecurityInfo API 函数完成的。 您需要授予的访问权限是
SERVICE_START
和SERVICE_STOP
。 您可能还需要授予他们GENERIC_READ
权限,具体取决于这些用户所属的组。 所有这些权利均在MSDN 中进行了描述。下面是一些执行此设置的 C++ 代码,假设感兴趣的用户位于“远程服务控制器”组(您将创建的)中,并且服务名称为“my-service-name”。 请注意,如果您想要向用户授予访问权限,例如用户(不一定是个好主意),而不是您创建的组,则需要将
TRUSTEE_IS_GROUP
更改为TRUSTEE_IS_WELL_KNOWN_GROUP
代码>.该代码没有您想要添加的错误检查。 所有三个可能失败的函数(Get/SetNamedSecurityInfo 和 SetEntriesInAcl)均返回 0 以指示成功。
另一个注意事项:您还可以使用SC 工具设置服务的安全描述符,可以在 %WINDIR%\System32 下找到,但这不涉及任何编程。
这也可以使用 P/Invoke 从 C# 中完成,但这需要更多工作。
如果您仍然特别希望能够以这些用户的身份枚举服务,则需要在 SCM 上向他们授予
SC_MANAGER_ENUMERATE_SERVICE
权限。 不幸的是,根据MSDN,SCM的安全性只能在Windows上修改服务器 2003 sp1 或更高版本。Note: This doesn't address enumerating services as a different user, but given the broader description of what you're doing, I think it's a good answer.
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:
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 requireSC_MANAGER_CONNECT
, but according to MSDN that should be granted to remote authenticated users.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
andSERVICE_STOP
. Depending on exactly which groups these users belong to, you might also need to grant themGENERIC_READ
. All of these rights are described in MSDN.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
toTRUSTEE_IS_WELL_KNOWN_GROUP
.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.
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.
This could also be done from C# using P/Invoke, but that's a bit more work.
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.感谢查理的那行代码。 这就是我最终所做的。 我从这个网站得到了这个想法:http://www.codeproject。 com/KB/cs/svcmgr.aspx?display=Print
我还必须将我正在访问的帐户添加到服务器上的 Power Users 组。
这是我的另一个带有 ImpersonationUtil.Impersonate() 的类:
Thanks for that line of code Charlie. Here's what I ended up doing. I got the idea from this website: http://www.codeproject.com/KB/cs/svcmgr.aspx?display=Print
I also had to add the account I'm accessing this as to the Power Users group on the server.
And here's my other class with the ImpersonationUtil.Impersonate():
您可以尝试在 web.config 文件中使用 ASP.NET 模拟并指定具有适当权限的用户帐户:
查看 MSDN 上的这篇文章。 我相信还有其他选项不需要将密码存储在 web.config 文件中,例如将其放在注册表项中。
这将导致 ASP.NET 辅助进程在指定用户的上下文中运行,而不是在登录到 Web 应用程序的用户的上下文中运行。 但是,这会带来安全问题,我会强烈重新考虑您的设计。 您可能需要考虑让 ASP.NET 网页依次向实际控制服务的其他进程(甚至另一个 Windows 服务)发出请求,或者将请求写入 Windows 服务定期轮询的数据库表。
You can try using ASP.NET impersonation in your web.config file and specify a user account that has the appropriate permissions:
Take a look at this article on MSDN. I believe there are other options that do not require storing the password in the web.config file such as placing it in a registry key instead.
This will cause the ASP.NET worker process to run under the context of the specified user instead of the user logged into the web application. However, this poses a security issue and I would strongly rethink your design. You may want to consider having the ASP.NET web page in turn fire off a request to some other process that actually controls the services, even another windows service or write the request to a database table that the windows service polls periodically.