Service Issues

[Previous] [Next]

When you first start developing services, you'll notice that some aspects might not work the way you expect. Services are special beasts that run in special operating environments. In this section, I'll discuss some of the issues you will probably encounter. However, I won't spend too much time on them here because they are all explained much more thoroughly in other chapters of this book. I just want to give you an idea of what to keep an eye out for.

LocalSystem vs. Specific User Account

In this section, I'm going to explain how running a service under the LocalSystem account differs from running the service under a specified user account.

The LocalSystem account is an account given to the operating system itself. The operating system is never restricted from accessing resources. A service running under the LocalSystem account can manipulate any directory or file, change the system's time, start or stop any other service, shut down the machine, and perform a whole slew of other normally restricted actions without any hindrance whatsoever. A LocalSystem service is considered to be part of the system's Trusted Computing Base (TCB).

NOTE
This is the government definition of Trusted Computing Base, which I found at http://nsi.org/Library/Compsec/compglos.txt:

"The totality of protection mechanisms within a computer system—including hardware, firmware, and software—the combination of which is responsible for enforcing a security policy. A TCB consists of one or more components that together enforce a unified security policy over a product or system. The ability of a TCB to correctly enforce a security policy depends solely on the mechanisms within the TCB and on the correct input by system administrative personnel of parameters (e.g., a user's clearance) related to the security policy."

Naturally, all kernel-mode code—hardware device drivers, memory management, file system, security monitoring, thread scheduling, and so on—is part of the system's TCB. Having a service run in the TCB is incredibly powerful, which is why only administrators of the machine have the privilege to install a service.

So if the LocalSystem account is so powerful, why would you ever want a service to run under a specific user account? Yes, it's true, LocalSystem services are all-powerful on the local machine but, by default, they can't do a whole lot on the network. For example, a LocalSystem service can't access shared directories, files, or printers on another machine because the local machine's LocalSystem account can't be authenticated on the remote machine. With Windows 2000, Microsoft has improved this situation: when computers are part of a domain, you can now treat a machine like a user account and grant the machine its own permissions.

If you are not running your service on a machine that is part of a domain and your service needs to access network resources, here is what you can do:

  • Have the service run under a specific user account that has been granted access to the network resource. Note that doing so will restrict what the service can do on the local machine.
  • Access resources using a protocol that doesn't require authentication. For example, a LocalSystem service can communicate via sockets, named pipes, or mailslots. Of course, this communication requires that the remote machine support incoming requests by using these protocols. These connections are referred to as NULL sessions and can be controlled by setting the NullSessionPipes and NullSessionShares data values that exist under the following registry subkey:
  • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ LanmanServer\Parameters

    You can also enable all pipes and shares on the machine to be accessed by all NULL session connections by setting the RestrictNullSessionAccess data value (located under the same subkey) to 0. Even though you can do this, you should not because it opens a huge security hole on the system.

  • Access resources after impersonating a specific user. To do this, you can call the various impersonation functions offered by Windows. (Impersonation is discussed in the chapters in Part IV of this book.) A service can also impersonate a specific user by having the LocalSystem service call the LogonUser function, passing a domain, username, and password to be authenticated. Note that the LogonUser function requires the TCB privilege (also known as the "Act as Part of the Operating System" privilege) that is granted, by default, to the LocalSystem account only—how convenient!

LocalSystem vs. Specific User Registry Subkeys

The registry is broken down into two main keys. The first key, HKEY_LOCAL_MACHINE, is where all the system-wide settings are stored. A service or an application can always read any settings under the HKEY_LOCAL_MACHINE key.

The second key, HKEY_USERS, is where each user's user-specific settings are stored. This key is further broken down into two types of subkeys. The first type of subkey is a specific user subkey. Each user account on the machine has a collection of registry settings that map to a subkey under HKEY_USERS. When the specific user logs on and becomes the interactive user, the familiar HKEY_CURRENT_USER key maps to the specific user's subkey under HKEY_USERS.

The second type of subkey under HKEY_USERS is called .DEFAULT, and it contains a user's default settings. When a new user account is created on the system, a new subkey is created under HKEY_USERS, and the settings in this subkey are populated with the current settings in the .DEFAULT subkey.

Like the settings under HKEY_LOCAL_MACHINE, the settings under HKEY_USERS\.DEFAULT are always available to services and applications, although a service is not likely to need to access it. A specific user's settings are not available under HKEY_USERS until that user has logged on to the system. Since services typically run under the LocalSystem account, a service should not attempt to access any specific user's settings under the HKEY_USERS account. Similarly, a LocalSystem service should not access the registry by using HKEY_CURRENT_USER. For more information about registry settings and user profiles, see Chapter 5.

Kernel Object Security

In this section, I introduce a common problem many developers run into when their client application and service run on the same machine and the client and service try to share a kernel object.

Here's the scenario. Your service starts running and calls CreateFileMapping to create a file-mapping object. CreateFileMapping creates a kernel object, so one of its parameters is the address of a SECURITY_ATTRIBUTES data structure. If you're like most programmers, you pass NULL for this parameter, which causes the kernel object to be created with default security. Notice that I said default security; I didn't say no security. Default security means that the object's access control is determined by the security context under which the object is created.

For example, a kernel object created by a LocalSystem service will, by default, allow full access to anything else running in the LocalSystem account, and will allow only read and execute access to members of the local administrators group. So if a LocalSystem service creates a file-mapping object with default security, an application running under a local administrators account can read from the file-mapping object but cannot write to it in any way. An application running under any other account will not be able to access the file-mapping object at all!

Right now, I just want to make you aware of this issue. Much more can be said about kernel object security for clients and services, and there are several ways to handle it, but they require that you have a much better understanding of Windows security. So I encourage you to read the security chapters in Part IV of this book to get the whole story.

Interactive Services, Window Stations, and Desktops

In this section, I'm just going to touch issues that affect how services interoperate with window stations and desktops. For more information about window stations and desktops, see Chapter 10.

When you create a kernel object, you can specify how it should be secured by passing the address of a SECURITY_ATTRIBUTES structure. But what about user objects such as windows and menus? User objects have a different model of use; they are not opened and closed—you just access them as you need them, which makes the code easier to write and enhances performance. Further, user objects existed in 16-bit Windows operating systems, which didn't support security in any form whatsoever. If Microsoft had added the SECURITY_ATTRIBUTES structure to CreateWindow and CreateMenu, developers would have had difficulty porting their 16-bit code.

Microsoft needed a way to secure user objects without affecting the existing functions and without affecting the way you used the objects. This is what window stations and desktops are all about. A window station is a logical combination of a keyboard, a mouse, and a display. The word "logical" means that the devices don't actually have to exist. When the system boots, it creates the interactive window station, named "WinSta0"; the physical keyboard, mouse, and display are assigned to this interactive window station. A window station also contains its own clipboard, a set of global atoms, and a group of desktop objects.

A desktop consists of a logical display surface and a set of user objects: windows, menus, and hooks. Threads are also associated with desktops. (See the SetThreadDesktop and GetThreadDesktop functions in the Platform SDK documentation.) If a thread associated with one desktop attempts to send a message to a window created on another desktop, the system fails the call. This is the security mechanism at work. Likewise, a thread can't install a hook on a thread that's part of another desktop.

Like window stations, desktops are identified by their string names. The WinLogon.exe process creates three desktops:

  • WinLogon Presets the Logon dialog box. After the user logs on, WinLogon.exe switches to the Default desktop.
  • Default The location where Explorer.exe and all the user's application windows appear. Whenever an application is run, it executes on this desktop.
  • Screen saver Runs the system's screen saver when the user has been idle for an extended period of time.

The system itself has its own special user account. So two "users" are effectively accessing a machine at one time: the LocalSystem user and the logged-on user. Certainly, if two users are running applications on a single machine, you don't want all the application windows visible on the single display device; both users would be clamoring for each other's screen real estate.

For this reason, the LocalSystem account is given its own window station, named "Service-0x0-3e7$" (the number is the service's logon SID), with its own desktop, named Default. The window station is noninteractive and does not have a physical keyboard, mouse, and display—the LocalSystem "user" is not an actual human being and therefore has no need to type, click the mouse, or "see" anything. Any application running on a desktop in this window station can create windows, but the windows will not be visible to the logged-on user. This is why services should never present a user interface: no one will ever see it, and the thread will be suspended as it waits for input, which can never be entered.

Using the Services snap-in, you can display the properties for a service. You might recall that the Log On tab contains an Allow Service To Interact With Desktop check box. When checked, this option causes the SCM to start a service on the interactive window station's default desktop: "WinSta0\Default". Notice that you can mark this check box only if your service runs under the LocalSystem account. This is because the LocalSystem account is highly privileged and is able to access the interactive user's window station and desktop.

One problem with a service interacting with the desktop is that the default desktop is not always visible. When the screen saver is running or the user logs off, the service's user interface remains on the Default desktop, but the user interface is not visible until the next user logs in. Another problem is that it makes the system quite vulnerable. For example, a normal application is able to send window messages to the service's window. Well, the application is running with the logged-on user's security context, but the application is now communicating with a process running as LocalSystem through an insecure channel. A restricted user can easily gain access to resources to which they should not be given access.

Here's an example: The service is running as LocalSystem and is presenting windows on the interactive default desktop. Normally, when the logged-on user attempts to use Task Manager's Processes tab to kill a service, an Access Denied or similar message is displayed, and the service continues running. This functionality is desired, of course. You wouldn't want a user who is logged on as a guest to kill the Server service, preventing other machines on the network from accessing directories, files, and printers (especially since the Server service runs inside Services.exe). However, if the LocalSystem service creates an interactive window, the logged-on user will see the window in Task Manager's Applications tab. Choosing End Task at this point sends a WM_CLOSE message to the window, which can kill the service.

NOTE
For all these reasons, Microsoft strongly discourages the use of the Allow Service To Interact With Desktop check box. In fact, an administrator can forbid services from interacting with the desktop by setting the NoInteractiveServices value to a nonzero value in the following registry subkey:

 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows 

So what about services that run under a specific user account? When the SCM launches a service executable under a specific account, the SCM first authenticates the user, using the supplied user name and password as part of the service's configuration information. (The user name is stored in the registry, and the password is stored in an LSA secret.) This authentication creates a logon session, which gets its very own noninteractive window station and desktop. The service executable is now invoked using this dedicated window station and desktop, and is called something like "UserAccountLogonSID\Default", where "UserAccountLogonSID" is a unique number generated during authentication.

This unique identification means that if you have two or more services set to run under the same user account, each will get its own logon SID, window station, and desktop (provided they're in separate processes)—the threads in these service executables will not be able to communicate by using user objects. This unique identification also means that if a service is running under the same account as the currently logged-on interactive user, the service's user interface will not be visible. In contrast, the LocalSystem account is authenticated just once, so multiple service executables running under the LocalSystem account all share the same window station and desktop and can communicate using user objects.

Microsoft has added some service-specific features to the familiar MessageBox(Ex) functions. First, when you pass the MB_SERVICE_NOTIFICATION flag, MessageBox(Ex) will display the message box on the interactive window station's active desktop regardless of whether the desktop is WinLogon, Default, or Screen Saver. This guarantees that the message box is visible on the display device.

Second, MessageBox(Ex) supports the MB_DEFAULT_DESKTOP_ONLY flag. This flag is similar to MB_SERVICE_NOTIFICATION except that it makes the message box visible only on the interactive window station's default desktop: a user must log on to see the message box. Note that MessageBox(Ex) does not return until a user has seen and dismissed the message box. By the way, to use either the MB_DEFAULT_DESKTOP_ONLY or the MB_SERVICE_NOTIFICATION flags, a service does not have to run under the LocalSystem account nor does its Allow Service To Interact With The Desktop option have to be selected. The system ensures that the message box is visible.

If you've been following along carefully, you've noticed that I have discouraged you from using every method I've described for creating an interactive service. If you want to produce a service that offers a user interface, what should you do? The answer is simple: create a separate, client-side application that uses some IPC mechanism (RPC, COM, named pipes, sockets, memory-mapped files, and so on) to talk to the service. I know that many people don't want to do this because they have to create a whole new project that produces its own executable, but creating a separate application is the correct and best-supported method. Microsoft simply can't break your architecture if you do this.

The client-side application could run on Windows 2000, Windows 98, UNIX, or any other operating system. You could create an HTML-based user interface that communicates with the service using ActiveX controls or Active Server Pages. You should also consider making your user interface a snap-in for MMC. Think of this client-side application as opening possibilities for you rather than restricting them because of all the user interface issues.

Before moving on, I'd like to discuss just one more user interface issue: some Windows functions produce hard-error message boxes. For example, the system will automatically display a message box if you are running an application from a CD-ROM drive and remove the disc. If the system didn't display a message box, its only other option would be to kill the process.

It is possible to modify the system's behavior so that hard errors are logged to the event log and do not cause message boxes to appear. To alter the system's behavior, you must modify the ErrorMode value in the following registry subkey:

 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows 

Table 3-4 lists the possible values for ErrorMode.

Table 3-4. ErrorMode values for configuring the display of hard-error message boxes

Value Description
0 (the default value) The system displays error message boxes.
1 For non-system-generated errors, an error message box is displayed. For system-generated errors, an entry is added to the event log and no error message box is displayed.
2 (best for an unattended server) For system-generated and non-system-generated errors, an entry is added to the event log and no error message is displayed.



Programming Server-Side Applications for Microsoft Windows 2000
Programming Server-Side Applications for Microsoft Windows 2000 (Microsoft Programming)
ISBN: 0735607532
EAN: 2147483647
Year: 2000
Pages: 126

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