Lessons from the School of Hard Knocks


We had some learning experiences along the way as we created our sample service. The first is that the SDK recommends using GetModuleFileNameEx to obtain the full path to a running executable. GetModuleFileNameEx now gives you the path in the form of \Device\ HarddiskVolume1\, not c:\. If you pass this form to CreateService, the service won’t start. We couldn’t find a simple way to map the \Device paths to drive letters, so one solution is to assume that the service’s current directory is where the binary exists. You can then first call GetCurrentDirectory, followed by GetModuleBaseName to append the binary name to the path. Note that simply using argv[0] will only give you what the user typed, not the full path.

Another issue that caused some consternation was that because we’d written the service to install and delete itself from the command line, and because both of these actions require administrator rights, it would seem to make sense to embed a manifest such as the one we documented in Chapter 2 and make the application always run as administrator. This works great as long as you’re running the service as local system, but as soon as you try and drop it down to local service, starting the service returns ERROR_ACCESS_DENIED. Neither sc.exe nor the Control Panel’s services applet bothers to tell you just where this access denied error happens–it could be accessing the service control manager or the service itself, or it could even be that the service fails and sets ERROR_ACCESS_DENIED as the error code. After writing some custom code to step through controlling the service, we observed that it was Start-Service that failed and that the debugging log was never created–which tells us ServiceMain was never executed. The conclusion is that you should create a Visual Studio command prompt running as administrator to install and remove your service and not embed a manifest in a service executable that causes it to always run as administrator.

The third problem we encountered was mentioned previously, but it’s worth mentioning again. If you restrict the service process’s token, your process may not have enough access to the objects it creates, and you’ll need to supply an ACL at creation time. This can be difficult to debug, because the handle returned when you create something will have full control access; you can do anything you like with that handle, but if you go to reopen the object to get a second handle, you can be denied access. Once you’ve seen the problem, it’s relatively easy to fix. If you suspect something like this is the problem, create a SECURITY_ATTRIBUTES structure, attach an initialized SECURITY_DESCRIPTOR to it, and then call SetSecurityDescriptorDacl to set a NULL DACL with bDaclPresent set to true. If whatever it is now works, you know it is an ACL problem. You must not leave the code this way–this is for debugging purposes only! You should then set a proper ACL on the object just as we did in the CreatePipe-Dacl function in the sample. We hope that our documenting these issues will save you some time and frustration.



Writing Secure Code for Windows Vista
Writing Secure Code for Windows Vista (Best Practices (Microsoft))
ISBN: 0735623937
EAN: 2147483647
Year: 2004
Pages: 122

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net