我希望我的服务运行不高,但作为恰好是管理员的用户(Windows / UAC)

时间:2011-06-21 19:12:30

标签: java windows service permissions uac

就像标题所说,我写了一个程序在后台运行',最好是作为Windows服务。 (它恰好用Java编写,服务部分由tanuki包装器提供,如果这很重要。另外,我正在运行Vista,但我假设这种情况发生在带有UAC的所有Windows版本上。)我运行服务作为'用户X'。

我还有一个配套的GUI程序,通常从开始菜单(无特权 - 即'asInvoker')运行 - 也称为'用户X'。

后台程序(又称服务)创建文件。我的主要需求是,无法使用的GUI程序能够读取,写入和删除由服务创建的这些文件。

只要“用户X”不是Administrators组的成员,这就可以毫无困难地工作。 (当然,创建服务需要管理员登录,但没关系。)

如果我关闭UAC,或者我将后台程序作为服务运行(例如,从命令提示符下),它也可以工作。

但是,当“用户X”是管理员的成员,并且后台程序作为服务运行时,我无法让它工作。

此问题的症状是流程资源管理器将我的服务流程显示为正在运行的特权(我从流程属性的“安全”选项卡中显示“BUILTIN \ Administrators - Owner”)。此外,该服务创建的所有文件都归“管理员”所有。

如果我从命令提示符运行我的后台程序无特权,则进程资源管理器显示'BUILTIN \ Administrators - Deny',程序创建的所有文件都归'User X'所有。

2 个答案:

答案 0 :(得分:1)

有趣的问题。我只是查了一些信息,似乎无法找到你最初提出的问题的答案,但我有一些其他建议。

首先,是否可以更改您的服务应用,以便创建所需的文件然后将其权限更改为您想要的?

其次,服务本身是否真的必须作为“用户X”运行?如果是这样,为什么?这种限制有什么办法吗?如果您可以绕过该要求,那么您可以让普通用户使该服务以。

的形式运行

第三,你最好说是一项服务,但并不是说这是一项要求。使用此环境是否允许您使用计划任务?任务调度程序本身作为系统服务运行,它产生其他进程来完成您设置的任务的工作。并且,在设置计划任务时,有一个选项(如果您使用GUI界面,则为复选框)以最高权限运行任务。如果你走这条路线,你可以让任务在登录时运行,或者你可以让它在系统启动时运行(在这种情况下,确保你没有选择“仅在登录时运行”)。否则,这应与您的服务设置类似。

根据您在下面的评论,我认为第三个建议可能仍然是一个选项。通过使程序以自己的方式处理它,您仍然可以获得与服务类似的状态信息。您的应用程序可以打开一个套接字以进行跨进程通信。后台进程可以在已知端口上打开ServerSocket,它可以侦听状态请求。

您的用户正在使用的客户端应用程序可能会尝试连接到此套接字。如果套接字连接,则进程正在运行,否则不会。

如果只想要“正在运行/未运行”状态,这就足够了,ServerSocket可以接受()连接,然后立即关闭并关闭生成的Socket;您甚至不必接受或发送任何信息,因为您只需要初始连接。

如果您希望保持启动/关闭任务的能力,您可以使用相同的ServerSocket来实现该功能。如果您没有将套接字用于任何其他数据(仅适用于上面提到的运行或未提及),您可以在接收到套接字上的任何数据后终止后台进程,无论它是什么,以及客户端(或用于关闭后台进程的任何内容)只需连接并发送一个字节而不是连接并立即断开连接。

对于启动,如果要将后台进程限制为一个实例,可以通过几种方法轻松完成。我认为你应该能够通过任务调度程序配置它,只允许一个任务实例。即使不是,你可以让后台进程启动连接到给定的端口,否则它会监听它是否从其他东西获得连接,如果是,这是它的第二个实例,所以中止。或者,更简单的是,如果使用静态端口号,ServerSocket的创建应该会自动失败,所以让新的ServerSocket(myPort)自行失败,捕获异常并中止。因此,有三种不同的方法可以确保您的流程充当适当的服务。

要首先启动它,您可以告诉任务计划程序在用户登录时启动它,或者如前所述在系统启动时启动它。您还可以配置任务,以便用户可以自己启动它(如果由于某种原因它尚未运行),事实上,您甚至可以让用户与之交互的客户端检查进程的状态并可能自动启动它如果还没有开始 - 尝试创建一个新进程并执行exec()命令,例如“schtasks / run / tn”你的任务名称“”

我认为这涵盖了你提到的所有基础,然后是一些。以上所有内容都应该非常简单。如果您确定这可能是您想要采取的路线,如果我忽略了某些内容,或者您​​有其他标准进一步限制您,请再次告诉我们。

答案 1 :(得分:1)

最后,我实现了使用Windows计划任务的解决方法,类似于上面描述的,但是我没有实现自己的“启动/停止”界面,而是编写了一个管理程序的Windows服务,作为任务。当服务启动时,它会启动一个任务,当要求服务停止时,它将停止该任务。因此,我不使用父级的套接字来查询子级是否正在运行,而是使用schtasks / Query并解析输出。为了在父进程退出时退出任务,我在我的应用程序中使用了RMI keepalive方法。

Windows计划任务对于可通过任务计划程序GUI修改的服务有一些不合需要的默认值,但不是通过schtasks的命令行选项 - 即ExecutionTimeLimit,DisallowStartIfOnBatteries,StopIfGoingOnBatteries。)但是可以使用以下选项查询和修改这些选项。 schtasks / Query和/ Create的'/ XML'选项。这就是我做的。

我还需要检测我是否在较新版本或较旧版本的Windows上运行,因为如果它是旧版本(没有UAC),那么这一切都是不必要的,但更重要的是,如果没有提供任务,那么定义任务将无法工作密码,因为schtasks的/ NP选项不可用。

我所知道的唯一的弱点(除了复杂)是由于schtasks关于/ NP选项的说明 - “只有本地资源可用”。这意味着无法访问映射的网络驱动器(我希望这就是它的全部意思。)我在Java中,在我的应用程序中需要独立实现SMB支持,所以这个弱点不是结束世界。

对于单个Win32调用可能完成的工作,这是很多工作。也许有一天我会弄清楚如何做到这一点。