使用网络服务账户发布到WMI时的权限问题

7
我正在为一个基于.NET Framework 3.5的Windows服务添加WMI发布功能,该服务在“网络服务”帐户下运行。
根据我在MSDN上找到的文档,默认情况下,“网络服务”帐户应具有WMI发布权限。 (“默认情况下,以下用户和组被允许发布数据和事件:...网络服务,...”)
然而,当服务调用Instrumentation.Publish(myStatusClassInstance)时,它会抛出DirectoryNotFoundException异常;
System.IO.DirectoryNotFoundException was unhandled
Message: Could not find a part of the path 'C:\Windows\system32\WBEM\Framework\root\MyWMINamespace\MyService_SN__Version_1.0.3686.26280.cs'.

看起来 System.Management.Instrumentation 试图动态生成代码,并且在以网络服务身份运行时,它会定位到一个网络服务没有权限的目录。
这个问题有什么最佳解决方法/变通之法?我能否在 app.config 或代码中覆盖代码生成目标目录?我不想在部署服务时去调整文件系统权限……
更新:我认为这是一个“特性”,旧版 FX 代码与 Win7 中较新的安全设置发生了冲突。WMI 管理类从注册表检索 WMI 安装目录,并将其用作生成代码的输出路径。不幸的是,很多用户不被允许(或不应该)在 %SystemRoot% 下写入东西……我提交了一个 connect bug(#530392),希望微软能提供任何明确的解释和/或提供修复或变通之法。
更新2:我猜对于普通用户账户来说,这不是问题,因为 UAC 虚拟化会启动并将文件存储在其他地方。然而,显然“网络服务”账户不受 UAC 虚拟化的保护……(?) 更新3: 增加了550pt的赏金。简单约束条件:基于.net framework 3.5的Windows服务,作为网络服务运行,在Win7和Win2008[RTM和R2]上需要能够通过System.Management.Instrumentation使用WMI发布数据,在默认权限/安全设置下且不使用反射修改框架内部/私有成员。欢迎使用“开箱即用”但干净的解决方案。如果SO允许,我将打开第二个相关赏金-Q作为另一个550pt的占位符。

赏金更新: 我打算通过第二个与此问题配合的问题来将赏金加倍,并将其作为赏金占位符:
https://stackoverflow.com/questions/2208341/bounty-placeholder(<-- 显然这是不被允许的,所以赏金占位符问题被 SO 礼仪警察关闭了。)

更新4: 这变得越来越好了。我注意到installutil将缺失的文件写入c:\windows\syswow64...等等,所以我意识到我在使用32位版本的installutil安装服务,但服务却作为64位进程运行。显然的副作用是当installutil运行时生成的代码最终会出现在syswow64(32位系统目录)下,而服务却在64位系统目录(system32)下寻找它。(<--离题了,但我真的很喜欢MSFT如何交换这些名称...:))。

因此,我尝试使用64位版本的installutil安装服务。但在%sysroot%\wbem\framework...等路径中出现权限错误,导致失败。接下来,我重新编译了x86的服务,并再次使用32位版本的installutil进行注册。结果出现了一个全新的异常:

System.Exception: The code generated for the instrumented assembly failed to compile.
   at System.Management.Instrumentation.InstrumentedAssembly..ctor(Assembly assembly, SchemaNaming naming)
   at System.Management.Instrumentation.Instrumentation.Initialize(Assembly assembly)
   at System.Management.Instrumentation.Instrumentation.GetInstrumentedAssembly(Assembly assembly)
   at System.Management.Instrumentation.Instrumentation.GetPublishFunction(Type type)
   at System.Management.Instrumentation.Instrumentation.Publish(Object instanceData)
   at SomeService.InstanceClass.PublishApp(String name) in e:\work\clientname\SomeService\SomeService\WMIProvider.cs:line 44
   at SomeService.SomeServiceService..ctor() in e:\work\clientname\SomeService\SomeService\SomeServiceService.cs:line 26
   at SomeService.Program.Main() in e:\work\clientname\SomeService\SomeService\Program.cs:line 17

越来越接近了...


你确定失败是由于访问权限吗?我建议使用SysInternals工具。 - lsalamon
好的观点。我是基于网络服务和大多数其他用户不再被允许在%systemroot%下编写/创建来做出这种假设的... ...我会检查是否能找到任何证据表明这个例外可能掩盖了另一个例外... - KristoferA
3个回答

2
我认为问题不在于发布数据,而是第一次在WMI中注册该类型。
如果您检查反汇编器中的System.Management.Instrumentation代码,例如Reflector,您会发现当要发布的程序集尚未注册时,代码将尝试注册程序集并将程序集信息保存在WBEM安装文件夹下的特定子目录中。
我怀疑如果您首先以管理员身份运行用于发布WMI数据的代码,它会注册程序集,然后Network Service账户将拥有执行常规发布所需的权限。

它报告自己已注册(无论如何,installutil都是这样说的)。此外,调用Instrumentation.IsAssemblyRegistered返回true,因此至少它“认为”自己已注册。当我调用Instrumentation.Publish时,会引发异常。 - KristoferA
IsAssemblyRegistered返回true,但RegisterAssembly抛出与Publish相同的异常。所以是的,你有点眉目了... :) - KristoferA

2
您是否使用了 installutil 来检查您的程序集?这应该会给您一份安装问题的日志。但由于您无法将其作为 Network Service 帐户运行,因此可能无法显示您遇到的问题。
此外,您确定这个服务必须在 Network Service 帐户下运行吗?
由于在特权帐户下运行 Windows 服务存在漏洞风险,Microsoft 创建了一些带有一定限制的特殊服务帐户,这些限制在 Vista 和 Win7 中得到了加强。自 Vista 以来,Microsoft 已经限制了在此帐户下运行的服务数量,而支持较低权限的服务数量增加了(请参见本文)。Network Service 帐户(也称为“NT AUTHORITY\NETWORK SERVICE”)可以访问网络(作为本地计算机帐户 PCNAME$),但在本地计算机上它的权限受到了限制(不像 Local System 帐户)。
您是否已经检查了您的程序集所使用的 WMI 安全权限分支?运行 wmimgmt.msc 并深入挖掘...当我对一些随机分支进行了快速检查时,我发现 Network Service 帐户没有写入权限。
最后,我建议使用 Sysinternals' ProcMon 工具,它可以让您仅过滤该进程并查看文件或注册表设置中是否存在任何访问拒绝错误。多年来,这个工具已经为我解决了很多问题。

谢谢回复。Installutil 只报告成功。Procmon 报告与问题中的异常相同;CreateFile 在找不到路径时失败...我会研究一下 WMI 权限... - KristoferA
网络服务在我要写入的WMI命名空间中没有完全的写入权限,因此我授予了它这些权限。然而,不幸的是,这并没有解决问题。 - KristoferA

1

1
是的,我就是那个提交了连接错误的人。我在问题中也包含了一个链接... - KristoferA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接