Although these are not the only security-related information structures, the following four structures are certainly the “heavy-hitter” structures used for keeping track of Windows NT security-related information:
Although these are structures, you’re required to consider them as opaque, meaning initializing them and setting their values must be accomplished by means of the supplied appropriate API functions. We’ll discuss exactly which functions should be used for manipulating each structure after we examine the structures themselves.
WARNING
As the SDK points out, you should never try to manipulate these security structures directly. There are API functions available for you to use to initialize these structures and politely “modify their guts.”
Each user logged on to an NT system is assigned an access token. This token is checked against SDs of any objects that the user is trying to access. The access token contains user privileges; security descriptors contain access rights.
Inside the SD are the collected pieces of information that together exactly specify the owner, permitted users and groups, and permissions granted (or denied) to particular users or groups of users of that object.
Subelements of the SD include the owner and group security identifiers (SIDs), as well as two Access Control Lists (ACLs).
NOTE
Again, the security API provides an entire array of functions for querying and manipulating the various security structures. Because these are structures, rather than OOP (object-oriented programming) objects, the way you interact with them is by using appropriate API functions, which expect as a parameter a pointer to a particular type of security structure.
SIDs An SID is a structure of variable length that uniquely refers to a user or group of users. Internally, an SID contains (among other things) a 48-bit authority value, which is a unique value comprised of a revision level, an identifier-authority value, and a subauthority value.
Once an SID is created, an NT system will not permit it to ever be reused, even if the SID is deleted. The SD of each object contains two SIDs:
Note that SIDs are used in several other areas of NT security. Every access token, for example, contains an SID that identifies the groups that user is a member of. Also, each Access Control Entry (ACE) in an ACL has its own SID that specifies the individual or group being granted or denied a set of permissions or rights.
ACLs An ACL is a list of rights or restrictions placed on a user or group for a given object (or group of objects). Each SD can contain two types of ACLs:
These ACLs are identical in form. Both types can contain zero or one or more Access Control Entries (ACEs). Each ACE contains three parts: users or groups this ACE pertains to, which rights are affected, and whether the rights are being granted or revoked.
An ACL can be in one of three states:
WARNING
Do not confuse a NULL DACL with an empty DACL! They are actually opposites in their effect. An empty DACL (the initial state in a new SD) means no access has been granted. A NULL DACL means no restrictions exist for the object, so it is accessible to all users. A DACL only becomes NULL by being set that way explicitly.
So, you should now understand, at least in theory, how an object’s access is specified for any condition: complete access, no access, access granted to some, and access restricted to some.
Self-Relative versus Absolute SDs SDs can be represented in either absolute or self-relative format. Figure 20.2 illustrates how these two formats differ.
SDs contain fields (the ACLs) that hold a variable number of entries (ACEs), and each field could be either NULL or empty. Therefore, it is much easier to update (add and remove) entries and settings in an SD if the SD itself is stored in memory as a structure of pointers (to structures with other pointers, usually). Otherwise, each time anything changed, a larger chunk of memory would need to be allocated, and the entire structure would need to be copied to the new area along with the new changes. This “update-friendly” format that makes use of pointers is called (somewhat confusingly) absolute format.
On the other hand, because pointers point to RAM, and RAM is generally only accessible by the computer owning it, it would not work very well to send an SD across the network (or save it to disk) because you would be sending (or writing) only a set of pointers, instead of the various structures themselves. Therefore, the SD can be stored in a second format where the entire structure, including all its current fields, is stored in one contiguous block of memory. This more “transfer-friendly” format is called self-relative format. As you might surmise, this is the format in which SDs are returned to you when you request them from the system. You can look at (read) the SD in this format, but when you need to change (write to) the SD, you must first convert the SD into absolute format.
Fortunately, there are two API functions you can use to do this conversion: MakeAbsoluteSD and MakeSelfRelativeSD. Unfortunately, you will need to use them each and every time you get or put an SD and also need to make changes to the SD.
Figure 20.2: SDs come in two flavors: the absolute, which is useful for updating the SD’s fields, and the self-relative, which is better suited for *transferring* the SD to a file, a different process, or across the network.