Permissions issue when publishing to WMI under net

2019-04-24 18:07发布

I'm adding WMI publishing to a .net framework 3.5 based windows service that is running under the 'network service' account.

According to a document I came across on MSDN, the 'network service' account should by default have WMI publishing permissions. ("By default, the following users and groups are allowed to publish data and events: ... Network Service, ...")

However, when the service calls Instrumentation.Publish(myStatusClassInstance), it throws a 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'.

..so it looks like System.Management.Instrumentation tries to generate code on the fly, and when running under network service it targets a directory where network service has no permissions.

What is the best fix/workaround for this? Can I override the code-gen target dir in app.config or in code? I don't want to have to fiddle around with file system permissions when deploying the service...

Update: I think this is a 'feature' where older FX code clashes with newer security settings in Win7. Internally the WMI managed classes retrieves the WMI installation directory from registry, and uses that as the output path for generated code. Unfortunately a lot of users are not allowed to (or supposed to) write stuff under %SystemRoot%... ...I filed a connect bug (#530392) to see if MSFT can bring any clarity and/or provide a fix or workaround.

Update 2: I'm guessing that for normal user accounts this is not an issue, because UAC virtualization will kick in and store the files elsewhere. However, apparently the 'network service' account is not covered by UAC virtualization..(?)

Update 3: Added 550pt bounty. Simple constraints: .net framework 3.5 based windows service, running as network service, need to be able to publish data through WMI using System.Management.Instrumentation on Win7 and Win2008[RTM & R2] with default permissions/security settings and without resorting to modifying framework internal/private members using reflection. 'Out-of-the-box' but clean solutions welcome. Will open a second related bounty-Q as a placeholder for another 550pt if SO allows.

Bounty update: I intend to double the bounty for this Q through a second hand-in-hand question that will serve as a bounty placeholder:
https://stackoverflow.com/questions/2208341/bounty-placeholder ( <-- Apparently this was not allowed, so the bounty placeholder question got closed by the SO etiquette police.)

Update 4: This gets better and better. I noticed that installutil was writing the missing files to c:\windows\syswow64...etc..., so I realized that I was using the 32-bit version of installutil to install the service, but the service was running as a 64-bit process. The obvious side effect was that code generated when installutil was running ended up under syswow64 (the 32-bit system directory), while the service was looking for it under the 64-bit system directory (system32). (<-- off topic, but I really like how MSFT managed to switch around the names there... :) ).

So I tried installing the service with the 64-bit version of installutil. That failed miserably with permission errors in the %sysroot%\wbem\framework...etc... path. Next I recompiled the service as x86 and registered it again using the 32-bit version of installutil. That resulted in an entirely new exception:

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

...getting closer...

3条回答
萌系小妹纸
3楼-- · 2019-04-24 18:32

I believe the problem is not with publishing data, but with registering that type in WMI for the first time.

If you examine the System.Management.Instrumentation code in reflector, or some other disassembler, you'll see that wen the assembly that is about to publish hasn't been registered, then the code will try to register the assembly and save the assembly info in a specially named sub directory under the WBEM installation folder.

I suspect that if you run code to publish the WMI data as an administrator first, it would register the assembly and then the Network Service account would have the permissions to do the normal publishing.

查看更多
唯我独甜
4楼-- · 2019-04-24 18:41

Have you inspected your assembly with the installutil? That should give you a log of the installation issues. (But since you can't run it as the Network Service account, it might not show the problem you're having.)

Also, are you sure this service must be run under the Network Service account?

Because of the vulnerability risk in running Windows services in privileged accounts, Microsoft has made these special service accounts with some limitations, which were strengthened in Vista and Win7. Since Vista, Microsoft has limited the number of services running under this account in favor of less-privileged ones (see this article). The Network Service account (aka "NT AUTHORITY\NETWORK SERVICE") can access the network (acting as the local machine account PCNAME$), but it has reduced rights on the local machine (unlike the Local System account).

Have you checked the WMI security permissions for the branch your assembly is using? Run wmimgmt.msc and dig in... When I did a quick check of some random branches, I could see that the Network Service account did not have write rights.

Lastly, I would suggest using Sysinternals' ProcMon, which would allow you to filter to just that process and see if there are any Access Denied errors in file or registry settings. This tool has solved many problems for me over the years.

查看更多
登录 后发表回答