Security Attributes

You cannot do much programming in the Win32 API without running into the many Kernel object-manipulation functions, which always take a pointer to a SECURITY_ATTRIBUTES structure. Take CreateFile, for instance, which is defined as follows:

HANDLE CreateFile( 
      LPCTSTR      lpFileName,             // pointer to name of file 
      DWORD        dwDesiredAccess,        // access (read-write) mode 
      DWORD        dwShareMode,            // share mode 
      LPSECURITY_ATTRIBUTES  lpSecurityAttributes,//  (see below)
      DWORD        dwCreationDistribution, // create mode
      DWORD        dwFlagsAndAttributes,   // open, delete, close attributes 
      HANDLE       hTemplateFile  );       // optional source for attributes 

What! All this just to create a file? You may take one look at this and decide to go back to using their favorite “normal” means of opening files: fopen, OpenFile, or Delphi’s Reset, for example.

But CreateFile has far more uses than its name implies. In a Win32 application, it is the primary means of opening all sorts of objects in addition to files; it opens pipes, mailslots, communications sessions, disk devices, and so on. CreateFile is not only used for creating these objects, but can also be used for opening, closing, and even deleting them, given the right combinations of flags. As you learned in Chapter 15, CreateFile is also capable of doing both synchronous and asynchronous (overlapped) I/O operations.

Performing any of these CreateFile operations on a secured object causes NT’s built-in security checking to go to work. NT compares access rights contained in your lpSecurityAttributes structure with any permissions or restrictions that have been placed on the object and causes your function to succeed or fail, as appropriate.

Typically, you would most often use CreateFile by simply filling in a NULL value for the lpSecurityAttributes. This is fine for routine object access, because when you specify the NULL value, the default set of SECURITY_ATTRIBUTES for the current process is used, which in most cases is exactly appropriate. This is also, by the way, exactly what happens when you open files using fopen, OpenFile, or any other means of file access under NT. As you might guess, all these functions behave similarly because they trace right back to the same code (and security checking) as used by CreateFile itself.

If you want anything more sophisticated than the default security behavior provided by using a NULL value for your SECURITY_ATTRIBUTES structure, you need to supply an actual SECURITY_ATTRIBUTES structure. Roll up your sleeves and prepare to do some rather strenuous mental exertion.

The SECURITY_ATTRIBUTES Structure

The SECURITY_ATTRIBUTES structure looks benign and simplistic at first glance:

typedef struct _SECURITY_ATTRIBUTES { 
    DWORD  nLength; // set this to sizeof( SECURITY_ATTRIBUTES );
    LPVOID lpSecurityDescriptor; // “complex” structure.
    BOOL   bInheritHandle; // whether child process inherits handle.
} SECURITY_ATTRIBUTES; , *LPSECURITY_ATTRIBUTES;

Setting the nLength field is simple (and important!). Setting the bInherithandle flag is straightforward enough—it’s a Boolean value. However, that middle field, which is actually a pointer to a SECURITY_DESCRIPTOR, is where the rubber really hits the road, in a security sense.

The security descriptor (SD) is one of the four major data structures used by NT’s security API. (The SECURITY_ATTRIBUTES doesn’t count as “major,” because it’s only a wrapper for supplying the SD to NT.) As mentioned earlier, the SD represents an object or a group of objects to NT’s security system. It makes sense that the various Win32 API functions dealing with securable objects each takes a SECURITY_DESCRIPTOR by encapsulation in the SECURITY_ATTRIBUTES structure.

Let’s take a look at each of the four main types of security structures, including the SECURITY_DESCRIPTOR, so that you will better understand how Windows NT  handles security.

© 1998 SYBEX Inc. All rights reserved.