March 1998
Why Do Certain Win32 Technologies Misbehave in Windows NT Services?
Download service2.exe (52KB)
Frank Kim is a support engineer for Microsoft specializing in Kernel/Base technologies. He enjoys spending his free time playing the stock market. He can be reached at franki@microsoft.com.
|
Four years ago
I was introduced to Windows NT® services. Like many other programmers, I found the M both interesting and bizarre. Unlike a Windows®-based application, services usually do not have any direct user interaction. Developers often tell me that some piece of code works from their Windows-based application but not from their service. The major problem is a lack of understanding in the "environmental" differences. The service's "environment" or outlook is very different from the "environment" a Windows-based or console application launched by the user encounters. What I mean by "environment" refers not only to the environment variables for the process; you also have to include window stations and desktops, registry hives, and loads of security.
Many Win32® technologies, such as MFC, ODBC and MAPI, can behave differently in a service, owing to the differences in the service's "environment." Let's explore why the Se different technologies appear to misbehave in a service. Before I explain the "environmental" differences, let's go over what a service is, exactly. A service is a background Win32 process with special requirements. It requires a unique entry point and a callback function. The callback function is referred to as the service control handler. The new entry point is usually called ServiceMain, but you can name it anything you want through the LPSERVICE_ MAIN_FUNCTION member in the SERVICE_TABLE_ ENTRY structure. |
|
The service is manipulated (installed, started, stopped, and configured) through a subset of the Win32 API. You can pass a server name to manipulate services remotely over a network. A service can be configured to run in either a specific user account or the LocalSystem account (see Figure 1). Either account is referred to as the service account. A service can be configured to start running when the system is first booted or at the discretion of a user with the proper security. |
Figure 1 Configuring a Service |
AlerterFor further information, please refer to the Platform SDK documentation and "Design a Windows NT service to Exploit Special Operating System Facilities," by Jeffrey Richter (MSJ, October 1997). I'd like to emphasize that a process launched from a service using the CreateProcess API is not a service itself and should not be referred to as a service. It is definitely a background process running in the same "environment" as the servicebut that's it. The documentation of the Windows NT Resource Kit misleads users into thinking that using the Srvany utility will magically turn their application into a service. This is not true. The utility just launches your application via a CreateProcess API call. This is very similar to the AT command available on Windows NT. But even though your app launched via CreateProcess is technically not a service, it is still running in the same "environment," so many of my comments will also apply to it. In this article, I will describe the environmental differences between a service and a process launched by the interactive user. I define the interactive user as somebody who logs onto a Windows NT machine via the Ctrl+Alt+ Delete secured key combination dialog box (see Figure 2). |
Figure 2 Logon Dialog |
Windows NT Security
|
Figure 3 Security Components |
|
|
For most developers, passing NULL for this parameter
is sufficient. This is fine as long as all processes manipulating the securable object are running in the same
security context.
In a Windows NT service, this technique may or may not work. Service accounts allow a service to run as a different user. If you have ever looked at the services installed on a Windows NT machine, you know that a majority of the M are configured for the System account, also known as the LocalSystem account. The System account is a special account known only locally to your machine. This means that this account cannot be used to access network resources relying on NT LAN Manager (NTLM) authentication. the Se resources include file shares, named pipes, the registry, and access to a remote computer's eventlog or Service Control Manager. Why isn't this possible? NTLM authentication is based on encrypted credentials containing a username and password. If the Operating system encounters a user without any credentials, the user is regarded as having NULL credentials. When the system attempts to access a secured network resource based on NULL credentials, this is referred to as a NULL session. Access is only allowed if the remote machine allows NULL session access. This is configurable through the registry. (See Knowledge Base article Q122702 for more information.) the Only other workaround would be to impersonate a user with valid credentials or use a service account that has access to the secured network resource. Winsock and NetBIOS are not secured NTLM resources, so they don't run into the above security restriction. This seems likes a major problem. So why are so many services configured to use the LocalSystem account? The LocalSystem account is granted all privileges available on the Operating system. Privileges allow a user to manipulate various system resources, such as changing the system time, interactively logging on, and shutting down from a remote system (see Figure 4). |
Figure 4 User Manager Granting Privileges |
Window Stations and Desktops
|
Figure 6 Window Station and Desktops |
|
Figure 7 Interactive Processes versus Services |
One interesting thing to note is even though you may have two services configured for the same service account, each will have a unique window station and desktop since their logon SIDs are different. The user SID is the same but each will have a unique logon session since each were run in a separate service account logon session. This is not the case for interactive and noninteractive LocalSystem services since they are either associated with WinSta0 or Service-0x0-3e7$. Now why is it so important to know which window stations and desktops are associated with a service? The first problem is interactivity. If your service is not associated with WinSta0\Default, it will not be able to display any USER objects to the user by default. This means you cannot display a window or obtain user input. You can display a MessageBox for a noninteractive service. The key flag types are MB_SERVICE_NOTIFICATION and MB_ DEFAULT_DESKTOP. (Please refer to the Platform SDK docs for more information.) In addition, you can't install a window hook or even send messages. the Se two actions are relative to the desktop your process is associated with. You cannot do the Se two things without reassigning the process with the correct window station and desktop. This means that window hooks and messages cannot go across desktops. the Other two window station and desktop combinations based upon the service account's logon SID are nonvisible. As I just mentioned, processes associated with a nonvisible window station will never be able to display or receive input from the interactive user (except for the MessageBox using the two special flags). You can still create USER objectsbut the user will never see the M. One mistake a lot of service developers make is displaying a dialog box prompting a user for some information. When the service is tested, the developer will notice that the service is hanging. The hang is caused by the fact that the service is associated with a nonvisible window station. the Operating system has successfully created the dialog box. The problem is that the user can't see it. So how do you get your service to display and obtain information from the user? Write a client application for the user to launch. The client application would display and obtain information from the user and then use some sort of interprocess communication to send the information back to the service. The great thing about this is you don't have to worry about window stations and desktops. A drawback is that this requires the user to do something to start your client application. the Other method requires you to configure your service for the LocalSystem account specifying the service type as SERVICE_INTERACTIVE_PROCESS. This would associate your service with the correct window station and desktop. the Only problem is that the service would not have any network access through NTLM security. This can be resolved in one of two ways. NULL session access can be regulated on the server side via the registry. If the service developer has proper security access to the server, the registry keys can be changed to allow access for a LocalSystem process. Another way to do this would be to impersonate a user who has access to the NTLM secured network resource. the Only problem is the service must know the user's password to generate the user's token via the LogonUser API. Why can't a user configure the service for a service account and then just reassign the service with the interactive window station and desktop? The problem is security. the Only users with full access to the interactive window station and desktop are the LocalSystem account and the interactive user if there is one. The reason I mention full access is because users, who belong to the local Administrators Group have partial access to the interactive window station and desktop. Certain USER API calls may or may not work based on the security. The best bet is to work with full access using the local administrators account at your own risk. The access allowed ace for the interactive user is based on the group logon SID and not the individual user's SID. This means you may have a service configured for the same account as the interactive user but the group logon SIDs will be different. the Only way to allow a service configured for a service account to access the interactive window station and desktop would be for the interactive user to modify the security to allow the service access or have another process running in LocalSystem account do it. (See Knowledge Base article Q165194 for more information.) Now that you have a service configured for the interactive window station and desktop, what are some of the gotchas you can run into? The first consideration is what happens when the user logs out. If a service is interactive, does that mean the Default desktop is destroyed? No. The Default desktop is still there. the Only difference is that the Winlogon desktop is now the active desktop. When the next user logs on to the machine, the system will switch back to the Default desktop. Anything displayed by the user will be seen by the interactive user. One difference between an interactive service and a process launched by the interactive user is, of course, that a service can run when nobody is logged on. This leads to some interesting problems. For example, for security reasons the Operating system clears the global atom table when the interactive user logs out. If an interactive service relies on information stored in the global atom table, the information will disappear when the interactive user logs off. Another example is an auto-started interactive service. The Default desktop is not created until the first interactive user logs on. This means that an interactive service attempting to display information before the user logs on will run into problems. One last thing I want to discuss is that an interactive service is exposed to interactive users, who can kill the service via the Task Manager if the service has a top-level window. If you have a service running in the LocalSystem account, the interactive user doesn't have the necessary security to kill your process. Say you go into Task Manager and tab to the list of processes. If you hit the End Process button for a process running in the LocalSystem account, you'll get an "Access is denied" message box as expected. But if this service has a top- level window, you can tab to the list of applications in Task Manager. If you hit the End Task button, you can kill the service through this exposed window. One way to avoid this is to prevent your window from appearing in the applications tab. Create a hidden window; then make the visible window a child of this hidden window. Remember, make you service interactive only as a last resort. The best option would be to create an interactive client application.
Registry Hives
|
Figure 9 Regedt32.exe |
Wrap-up
From the March 1998 issue of Microsoft Systems Journal.
|