1

I'm having a bit of trouble with an application i'm developing. Here's the scenario: I have two Windows Services (Service A and Service B) written in C#.

Service A is responsible to transfer data between two applications (using WebServices, FTP connections, etc). It's also responsible to update Service B.

Service B is responsible to update Service A and update a Web Application.

The basic operation of updates is (lets say this is the process to update service A, done by Service B):

  1. Check for updates through WebServices
  2. If there is a new version, stop the service (using C# ServiceController).
  3. Backup current files of the service (so I can do a Rollback if something goes wrong)
  4. Uninstall the service (using sc delete command)
  5. Download the updated files of the service (using FTP connection)
  6. Execute some SQL Server scripts, if exist
  7. Install the Windows Service (using sc create command)
  8. Start Service (using C# ServiceController)

Everything runs smoothly until step 7. I figured that the problem is that the user doing the update (the user that runs Service B) does not have permissions to create new windows services, so SC Create always returns something like "[SC] OpenSCManager FAILED 5: Access is denied" Note that I had both services running with LocalSystem Account. So, I figured that this account cannot create new Windows Services (correct me if I've assumed wrong).

After this I've created a new Windows User, just to run the services. The idea was to give this user the necessary permissions (to network shared, files and create services). However, this user still can't create the service.

Here's what I've tried:

  1. Give the user cmd.exe and sc.exe permissions (using CACLS).
  2. Use PsExec to run cmd (with -i -s) instead of cmd.exe directly.
  3. Using the SubInAcl command so the user has permissions to the both Windows Service. But here's the thing, at the time I don't have any Service, so it doesn't work.

Some remarkes:

  • This Windows Services don't have any installer.
  • The SC command is run using C# ProcessStartInfo.
  • The SC command specifies the user and password of the Windows User that I've created.
  • I really don't want the Windows Services to be run under a user account with Administrative Privileges.

I know that this thread is similar to some already here Auto-update a Windows Service, however I cannot find any working solution anywhere.

Sorry for the long text

Community
  • 1
  • 1
Luís Cruz
  • 14,780
  • 16
  • 68
  • 100

1 Answers1

2

I think your basic design is brittle and flawed. You should not be deleting and creating services as part of normal service operation.

What I would do would be to arrange that any service that needs updating in place was capable of doing it by itself. Basically put all the code that is subject to update in a DLL. The code in the service EXE is just a thin host in charge of loading the main DLL and invoking it's main processing loop. When the EXE determines that it is time to update it downloads the new DLL, presumably checking via a hash that it downloaded correctly. Next the processing loop is terminated, the old DLL is unloaded, the new DLL is loaded and the processing loop started again.

This approach is much less intrusive and avoids all permission and rights issues. You can write a single service host EXE and have multiple DLLs containing the logic.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • +1 and it aids in testing/debugging since you can create a test suite for the DLL(s)... – Yahia Aug 23 '11 at 20:01
  • You'll need to be very careful here about threading. In particular, your handler callback function(s) will need to be in the service EXE and will need to cope properly with requests that come in while the DLL is being replaced. (And of course you'll have to make sure you don't unload the DLL while the handler callback function is still using it.) – Harry Johnston Aug 23 '11 at 22:17
  • @harry I said to terminate processing loop before the update cycle. In the design in the question the service is deleted so apparently it doesn't matter if it's non functional for a short window. – David Heffernan Aug 24 '11 at 05:06
  • Ok, this wasn't my brightest moment. Since I've already done all the code what I did was create a new DLL with all the code of the services EXE. Then I stop the service and replace the DLL. In fact, if the service is stopped, the EXE is not in use and I could overwrite the EXE itself. So the delete/create of services is really pointless. Next time I'll try to use a better solution like yours. Thanks for your insight. – Luís Cruz Aug 24 '11 at 13:19
  • @david As far as I know, there is no way to prevent the service manager from calling your handler function whenever it feels like it. I don't think you change the address of the handler function once it has been set, either. So the handler function must be in the EXE, and if it calls into the DLL it has to make sure it doesn't do so during the unload/load process, otherwise the service will crash. – Harry Johnston Aug 24 '11 at 21:56