Windows Services Programming 7

 

 

 

 

 

Service Control Programs

 

A service control program starts and controls services. It performs the following actions:

 

  1. Starts a service or driver service, if the start type is SERVICE_DEMAND_START.
  2. Sends control requests to a running service.
  3. Queries the current status of a running service.

 

These actions require an open handle to the service object.

 

Service Startup

 

To start a service or driver service, the service control program uses the StartService() function. The StartService() function fails if the database is locked. If this occurs, the service control program should wait a few seconds and call StartService() again. It can check the current lock status of the database by calling the QueryServiceLockStatus() function.

If the service control program is starting a service, it can use the StartService() function to specify an array of arguments to be passed to the service's ServiceMain function. The StartService function returns after a new thread is created to execute the ServiceMain function. The service control program can retrieve the status of the newly started service in a SERVICE_STATUS structure by calling the QueryServiceStatus() function. During initialization, the dwCurrentState member should be SERVICE_START_PENDING. The dwWaitHint member is a time interval, in milliseconds, that indicates how long the service control program should wait before calling QueryServiceStatus() again. When the initialization is complete, the service changes dwCurrentState to SERVICE_RUNNING. The service control manager does not support passing custom environment variables to a service at startup. Also, the service control manager does not detect and pass on changes to environment variables as the service is running. Instead of making a service dependent on an environment variable, use registry values or ServiceMain() arguments. The following is a simplified overview of what happens when a typical service is started by the service control manager:

 

  1. The SCM reads the service path from the registry and prepares to start the service. This includes acquiring the service lock. Any attempt to start another service while the service lock is held will block until the service lock is released.
  2. The SCM starts the process and waits until either the child process exits (indicating a failure) or reports the SERVICE_RUNNING status.
  3. The application performs its very simple initialization and calls the StartServiceCtrlDispatcher() function.
  4. StartServiceCtrlDispatcher() connects to the service control manager and starts a second thread that calls the ServiceMain function for the service. ServiceMain should report SERVICE_RUNNING as soon as possible.
  5. When the service control manager is notified that the service is running, it releases the service lock.

 

If service does not update its status within 80 seconds, plus the last wait hint, the service control manager determines that the service has stopped responding. The service control manager will log an event and stop the service. If the program is starting a driver service, StartService() returns after the device driver has completed its initialization.

 

Service Control Requests

 

To send control requests to a running service, a service control program uses the ControlService() function. This function specifies a control value that is passed to the HandlerEx() function of the specified service. This control value can be a user-defined code, or it can be one of the standard codes that enable the calling program to perform the following actions:

 

  1. Stop a service (SERVICE_CONTROL_STOP).
  2. Pause a service (SERVICE_CONTROL_PAUSE).
  3. Resume executing a paused service (SERVICE_CONTROL_CONTINUE).
  4. Retrieve updated status information from a service (SERVICE_CONTROL_INTERROGATE).

 

Each service specifies the control values that it will accept and process. To determine which of the standard control values are accepted by a service, use the QueryServiceStatusEx() function or specify the SERVICE_CONTROL_INTERROGATE control value in a call to the ControlService() function. The dwControlsAccepted member of the SERVICE_STATUS structure returned by these functions indicates whether the service can be stopped, paused, or resumed. All services accept the SERVICE_CONTROL_INTERROGATE control value. The QueryServiceStatusEx() function reports the most recent status for a specified service, but does not get an updated status from the service itself. Using the SERVICE_CONTROL_INTERROGATE control value in a call to ControlService() ensures that the status information returned is current.

 

Service User Accounts (SUA)

 

Each service executes in the security context of a user account. The user name and password of an account are specified by the CreateService() function at the time the service is installed. The user name and password can be changed by using the ChangeServiceConfig() function. You can use the QueryServiceConfig() function to get the user name (but not the password) associated with a service object. The service control manager (SCM) automatically loads the user profile.

When starting a service, the SCM logs on to the account associated with the service. If the log on is successful, the system produces an access token and attaches it to the new service process. This token identifies the service process in all subsequent interactions with securable objects (objects that have a security descriptor associated with them). For example, if the service tries to open a handle to a pipe, the system compares the service's access token to the pipe's security descriptor before granting access. The SCM does not maintain the passwords of service user accounts. If a password is expired, the logon fails and the service fails to start. The system administrator who assigns accounts to services can create accounts with passwords that never expire. The administrator can also manage accounts with passwords that expire by using a service configuration program to periodically change the passwords. If a service needs to recognize another service before sharing its information, the second service can either use the same account as the first service, or it can run in an account belonging to an alias that is recognized by the first service. Services that need to run in a distributed manner across the network should run in domain-wide accounts. You can specify one of the following special accounts instead of specifying a user account for the service:

 

  1. LocalService
  2. NetworkService
  3. LocalSystem

 

 

The Windows services log on accounts

 

LocalService Account

 

The LocalService account is a predefined local account used by the service control manager. This account is not recognized by the security subsystem, so you cannot specify its name in a call to the LookupAccountName() function. It has minimum privileges on the local computer and presents anonymous credentials on the network. This account can be specified in a call to the CreateService() function. Note that this account does not have a password, so any password information that you provide in this call is ignored. While the security subsystem localizes this account name, the SCM does not support localized names. Therefore, you will receive a localized name for this account from the LookupAccountSid() function, but the name of the account must be NT AUTHORITY\LocalService when you call CreateService(), regardless of the locale, or unexpected results can occur. The user SID is created from the SECURITY_LOCAL_SERVICE_RID value. The LocalService account has its own subkey under the HKEY_USERS registry key. Therefore, the HKEY_CURRENT_USER registry key is associated with the LocalService account. The LocalService account has the following privileges:

 

  1. SE_ASSIGNPRIMARYTOKEN_NAME (disabled)
  2. SE_AUDIT_NAME (disabled)
  3. SE_CHANGE_NOTIFY_NAME (enabled)
  4. SE_CREATE_GLOBAL_NAME (enabled)
  5. SE_IMPERSONATE_NAME (enabled)
  6. SE_INCREASE_QUOTA_NAME (disabled)
  7. SE_SHUTDOWN_NAME (disabled)
  8. SE_UNDOCK_NAME (disabled)
  9. Any privileges assigned to users and authenticated users

 

NetworkService Account

 

The NetworkService account is a predefined local account used by the service control manager. This account is not recognized by the security subsystem, so you cannot specify its name in a call to the LookupAccountName() function. It has minimum privileges on the local computer and acts as the computer on the network. This account can be specified in a call to the CreateService() function. Note that this account does not have a password, so any password information that you provide in this call is ignored. While the security subsystem localizes this account name, the SCM does not support localized names. Therefore, you will receive a localized name for this account from the LookupAccountSid() function, but the name of the account must be NT AUTHORITY\NetworkService when you call CreateService(), regardless of the locale, or unexpected results can occur.

A service that runs in the context of the NetworkService account presents the computer's credentials to remote servers. By default, the remote token contains SIDs for the Everyone and Authenticated Users groups. The user SID is created from the SECURITY_NETWORK_SERVICE_RID value. The NetworkService account has its own subkey under the HKEY_USERS registry key. Therefore, the HKEY_CURRENT_USER registry key is associated with the NetworkService account. The NetworkService account has the following privileges:

 

  1. SE_ASSIGNPRIMARYTOKEN_NAME (disabled)
  2. SE_AUDIT_NAME (disabled)
  3. SE_CHANGE_NOTIFY_NAME (enabled)
  4. SE_CREATE_GLOBAL_NAME (enabled)
  5. SE_IMPERSONATE_NAME (enabled)
  6. SE_INCREASE_QUOTA_NAME (disabled)
  7. SE_SHUTDOWN_NAME (disabled)
  8. SE_UNDOCK_NAME (disabled)
  9. Any privileges assigned to users and authenticated users

 

LocalSystem Account

 

The LocalSystem account is a predefined local account used by the service control manager. This account is not recognized by the security subsystem, so you cannot specify its name in a call to the LookupAccountName() function. It has extensive privileges on the local computer, and acts as the computer on the network. Its token includes the NT AUTHORITY\SYSTEM and BUILTIN\Administrators SIDs; these accounts have access to most system objects. The name of the account in all locales is .\LocalSystem. The name, LocalSystem or ComputerName\LocalSystem can also be used. This account does not have a password. If you specify the LocalSystem account in a call to the CreateService() function, any password information you provide is ignored. A service that runs in the context of the LocalSystem account inherits the security context of the SCM. The user SID is created from the SECURITY_LOCAL_SYSTEM_RID value. The account is not associated with any logged-on user account. This has several implications:

 

  1. The registry key HKEY_CURRENT_USER is associated with the default user, not the current user. To access another user's profile, impersonate the user, then access HKEY_CURRENT_USER.
  2. The service can open the registry key HKEY_LOCAL_MACHINE\SECURITY.
  3. The service presents the computer's credentials to remote servers.
  4. If the service opens a command window and runs a batch file, the user could hit CTRL+C to terminate the batch file and gain access to a command window with LocalSystem permissions.

 

The LocalSystem account has the following privileges:

 

  1. SE_ASSIGNPRIMARYTOKEN_NAME (disabled)
  2. SE_AUDIT_NAME (enabled)
  3. SE_BACKUP_NAME (disabled)
  4. SE_CHANGE_NOTIFY_NAME (enabled)
  5. SE_CREATE_GLOBAL_NAME (enabled)
  6. SE_CREATE_PAGEFILE_NAME (enabled)
  7. SE_CREATE_PERMANENT_NAME (enabled)
  8. SE_CREATE_TOKEN_NAME (disabled)
  9. SE_DEBUG_NAME (enabled)
  10. SE_IMPERSONATE_NAME (enabled)
  11. SE_INC_BASE_PRIORITY_NAME (enabled)
  12. SE_INCREASE_QUOTA_NAME (disabled)
  13. SE_LOAD_DRIVER_NAME (disabled)
  14. SE_LOCK_MEMORY_NAME (enabled)
  15. SE_MANAGE_VOLUME_NAME (disabled)
  16. SE_PROF_SINGLE_PROCESS_NAME (enabled)
  17. SE_RESTORE_NAME (disabled)
  18. SE_SECURITY_NAME (disabled)
  19. SE_SHUTDOWN_NAME (disabled)
  20. SE_SYSTEM_ENVIRONMENT_NAME (disabled)
  21. SE_SYSTEMTIME_NAME (disabled)
  22. SE_TAKE_OWNERSHIP_NAME (disabled)
  23. SE_TCB_NAME (enabled)
  24. SE_UNDOCK_NAME (disabled)

 

Most services do not need such a high privilege level. If your service does not need these privileges, and it is not an interactive service, consider using the LocalService account or the NetworkService account.

 

 

 

 

< Windows Services 6 | Win32 Programming | Windows Services Win32 Programming | Windows Services 8 >