来自同一可执行文件的多种服务
我编写了一个小型服务(普通Win32),我想知道当多个用户登录时是否可以运行该服务的多个实例。
基本上,假设我们有UserA和UserB,而UserA的服务将登录为" domain \ UserA",而UserB的服务将登录为" domain \ UserB",这当然来自同一可执行文件。我可以使用ChangeServiceConfig()函数动态地更改登录,但是看起来它是在整个系统范围内更改的,而我希望每个用户只有自己为他运行的服务副本。
预先感谢我们提供任何指导。
解决方案
Win32服务被设计为在整个系统范围内运行,并在任何用户登录之前就开始运行。如果希望每个用户运行某些东西,最好将其设计为常规应用程序并从用户的Startup运行它。团体。
服务的整个概念是,它在任何用户登录之前就已启动。因此,即使有可能,由于服务尚未登录,我们将无法在服务启动时在userA和userB之间进行选择。
一个可能的方向是该服务以SYSTEM身份运行,每隔几分钟检查是否有用户登录,是否假冒该用户并执行此操作。
服务是否有可能创建子进程,然后再采用用户凭证(或者从用户凭证启动)?这样,我们仍然仅限于服务的单个实例,但是它能够完全按用户执行其工作。 Windows任务计划程序IIRC会执行此操作。
是的,听起来很接近(我正在回答Greg的评论,但评论太短而无法满足我的答复)。
我事先不知道用户列表,但是有一个GUI控制应用程序可用于为每个用户输入用户名/密码对。因此,userA将登录,运行应用程序,输入其凭据,然后服务将使用该凭据。同时(在userA注销后,但该服务仍使用userA的凭据运行),userB登录,使用该应用程序,并且该服务的另一个副本以已登录的userB身份开始运行。因此,同时运行userA和userB服务。
那可能吗?
我们可能正在寻找模拟用户。在这里通过Google的快速搜索查看我发现的一些参考资料:
- 有关WindowsIdentity.Impersonate的MSDN文章
- .Net安全博客文章
听起来好像我们实际上在时间和身份方面有两个不同的,相互矛盾的要求。
- 以每个登录用户身份运行
- 即使没有用户登录,也会自动运行。
没办法简单地做到这一点,而是考虑将程序包装在服务中。该程序将在每个用户启动时正常运行(通过启动文件夹或者taskscheduler),此外,还将创建一个服务以系统用户(或者我们定义的任何其他用户)的身份运行应用。
由于我们还需要(在注释中提到此内容)该应用程序即使在最终用户注销后也仍可以继续运行,因此我们可以让该服务为我们管理此过程。
但是,这可能不是最好的主意,因为用户仍然可以有效登录。这可能会产生许多副作用,包括安全性,性能(一次登录的用户太多...)等。
我们可以创建一个服务应用程序和一个非服务(普通)应用程序,并使它们通过IPC(映射文件,管道,MailSolts ...命名)进行通信。
这样我们就解决了所有麻烦。
注意:相同的应用程序在作为进程启动时和由用户启动时的行为可能会有所不同,但最后还是一样,我们仍然有2个应用程序(无论我们只有一个可执行文件)。
可以使用不同的帐户运行。实际上,这很普遍。请参阅svchost.exe,它实现了许多OS服务。
我只是不知道我们如何确定哪个帐户。在一家大公司中,设置了许多PC,因此所有100.000+名员工都可以使用它。我们既不想以登录用户的身份运行服务,也不想为所有100.000用户运行它。那么我要问哪个账户呢?
Windows进程一次只能以一个用户的权限执行。这适用于服务和其他过程。有了足够的特权,就有可能通过模拟在不同用户之间"切换"。我们尝试执行的最常见的模式是拥有一个特权服务的实例,该实例进行注册以登录/注销事件并相应地创建子进程,每个子进程都模拟登录的用户。该模式还将简化UI,因为每个进程都在每个单独用户的桌面上运行,就好像它是常规应用程序一样。
如果使特权服务的代码尽可能简单,则此模式的添加好处是可以最大程度地减少代码的攻击面。如果用户在服务的"以用户身份运行"方面发现安全问题,则这不是问题,而特权服务中的安全问题可能会导致特权升级。实际上,在实施Windows消息处理循环的Vista特权服务之前,很容易受到称为Shatter攻击的攻击,在我们尝试执行此操作时,应该注意这一点。
我们不需要服务的多个实例。从问题的描述来看,我们似乎需要的是一项可以模拟用户并代表他们执行作业的服务。
我们可以通过实现服务中托管的COM对象来实现。客户端应用程序(最终用户运行)将在CLSID上调用CoCreateInstanceEx。这将导致在服务中创建COM对象的新实例。然后,应用程序可以在接口之一上使用一种方法来将收集的用户凭据传递给COM对象(尽管我会谨慎地收集凭据,而不是查看是否可以传递用户令牌)。然后,在服务上下文中运行的COM对象可以调用LogonUser()登录并模拟用户,因此它可以代表她执行任何操作(例如查找用户本地appdata文件夹:-)。其他答案具有很好的链接,可以使用凭据或者令牌来模拟用户。
如果我们对COM感到满意,建议我们将对象创建为多线程的(驻留在MTA中),以便COM不会序列化它们的执行。如果不是这样,那么默认的单线程模型将足以满足需求。
Visual Studio ATL向导可以生成位于服务中的COM对象的框架。我们还可以在此处阅读有关使用ATL实施Windows Service的信息:http://msdn.microsoft.com/zh-cn/library/74y2334x(VS.80).aspx
如果我们根本不了解COM,则可以使用其他通信渠道将凭据传递给服务。
无论如何,一旦服务获得了凭据,代表用户的所有工作都必须在后台线程上执行,以免阻塞以用户身份运行的应用程序。
我们希望它一直运行,因此需要服务。
我们需要跟踪每个用户的内容,因此需要一个在用户会话中运行并与服务通信的应用程序(使用命名管道或者DCOM或者任何符合我们要求的应用程序)。