Chapter 5: Creating Secure and Resilient


There are many new features added to Windows Vista that allow you to make your services more secure. In this chapter, we’ll give you a guided tour of these features, as well as show you how to create a service that communicates securely with the desktop. To demonstrate how these features work, we wrote a fully featured service that will be used for examples throughout the chapter. Writing a service in C/C++ requires a surprisingly large amount of code–a service that doesn’t do much still will add up to a few hundred lines of code. But much of the code is boilerplate and can be reused. This service has more than 1,100 lines of code (LOC) (including white space), and demonstrates communicating with clients across named pipes. If Watts Humphrey (Humphrey 2006) is correct, our sample service probably has 10 to 20 defects, but it was written to the standards of production code, and we hope that you can base a shipping application on this sample. Along the way, we encountered some lessons from the “School of Hard Knocks” involving how you actually work with services on Windows Vista, and this will hopefully save you from some of the difficulties we experienced. We’ll also have a discussion of the various options you might use for your service to communicate with desktop clients.

Services Overview

Windows services are used to run programs that need to operate independently of whether a user is logged on at a console. If you’re familiar with Unix or Linux, services are very analogous to daemons. Although we’re not going to go into detail about just how services work, it would be helpful for you to have an overview of how services function. For a full description, look at the “Services” topic in the Windows SDK documentation, especially the “Service Program Tasks” topic.

Services typically run under one of three specially defined service accounts, and can be configured to run as a user account. Service accounts will be covered in the next section. A service is just a normal executable program, except that it will make a number of special API calls to register entry points with the service control manager (SCM). It’s this author’s practice to write services that will install and remove themselves if invoked with the correct switches and that run as a service otherwise. This is because you can end up installing and removing your service many times during the development process, and the CreateService API takes 13 arguments, not counting the handle to the SCM. It’s also easier, since we’ll need the service name in multiple places in our service code.

The first task a service performs in its main function is to register the ServiceMain function with the service control dispatcher. This is almost all that the main entry point for the application will do, and if multiple services need to be supported within one process, multiple service names and entry points are registered. Whether to run multiple services in one process is a key decision from the standpoint of security, performance, and reliability. Regardless of how many services run in the same process, they’ll share the same address space, run under the same service account, and have the same privileges enabled.

ServiceMain calls yet more boilerplate code: the first thing it does is register the control handler for the service. If the service needs to be started, stopped, paused, or process newer controls (like logon events or hardware changes), the control handler function is where this will happen. The control handler function is called by the service control dispatcher and operates asynchronously with your service’s worker threads, so you’ll need a way for the control handler function to communicate with the thread or threads doing the work. Many implementations use events, but this example uses I/O completion ports, which can be a lot more efficient than events, largely because we’d need a lot of events to properly handle a named pipe and the control mechanisms, but we can do it all with one I/O completion port.

There are two control handlers defined, and in new code, you should use RegisterServiceCtrl-HandlerEx, which allows you to use the newer controls. Once the control handler has been registered, the service must update its control status to SERVICE_START_PENDING. If you need to do lengthy initialization, you need to repeatedly call SetServiceStatus with an updated wait hint to let the SCM know that your service hasn’t hung during start-up. Be careful to only send updates when you’re really making progress–just sending updates in a loop can have some nasty side effects on the operating system. Speaking of start-up, many services start on boot, and there are new options that allow your service to start just after boot, which tends to improve the user’s overall experience. Check the most recent Windows SDK for details on this. If the initialization doesn’t take much time, go ahead and set the status to SERVICE_RUNNING. Once the service status has been set to running, you should then go ahead and call the function in which you’re going to do the bulk of your work. Be sure and implement any code needed to communicate correctly with your control handler in this function, and make sure that the last thing the function does is to set the service status to SERVICE_STOPPED, with the appropriate exit code. Once ServiceMain returns and the status has been set to SERVICE_STOPPED, the service will exit, and if it is the only (or last) service running in that process, the process will exit as well.



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