In general, when people refer to "Windows security," they mean Windows implementation of access control. Access control can be defined as the assignment and enforcement of who can and cannot perform certain activities on securable objects. Windows applies access control to a number of system objects and provides a mechanism for securing custom objects as well.
The system enforces security on a number of objects and features provided by the system. Any object the system secures through access control is considered to be a securable object. Table 10-1 shows the types of securable objects in Windows 2000 as of the writing of this book. (The system also provides an enumerated type called SE_OBJECT_TYPE that includes a value for each type.) As you can see, many of the major components in Windows can (and do) take advantage of access control, including custom and private objects.
Windows 2000 allows your service software to subject application-defined objects of any type to Windows access control. The system manages the security of the object, whereas your software associates the security with the object and manages the functionality of the object itself. This security management is called private object security and is discussed in detail later in this chapter.
Table 10-1. Securable object types in Windows 2000
Category | SE_OBJECT_TYPE Enumerated Type | Description |
---|---|---|
File objects | SE_FILE_OBJECT | Files or directories on an NTFS file system. |
Service objects | SE_SERVICE | A service installed on a system or the Service Control Manager (SCM) of a system. |
Printer objects | SE_PRINTER | A printer or a print server. |
Registry keys | SE_REGISTRY_KEY | A registry key on a Windows 2000 system. |
Share objects | SE_LMSHARE | A share object indicating a shared directory on a Windows 2000 system. |
Kernel objects | SE_KERNEL_OBJECT | The system can secure each of the following kernel objects: process objects, thread objects, job objects, semaphore objects, event objects, mutex objects, file-mapping objects, waitable timer objects, access tokens, named pipes, and anonymous pipes. |
Window objects | SE_WINDOW_OBJECT | Window station and desktop objects (described later in this chapter). |
Directory services objects | SE_DS_OBJECT SE_DS_OBJECT_ALL | Windows 2000 allows you to apply security to objects in Active Directory or directory services. |
WMI objects | SE_WMIGUID_OBJECT | Objects exposed to WMI. |
Security provider objects | SE_PROVIDER_DEFINED_OBJECT | Windows 2000 supports replaceable security providers, and these can expose securable objects. |
Private objects | Custom objects created by a service or application secured by the system. |
One strength of access control in Windows is that the process of securing an object is largely the same from object type to object type. This common design makes it easier for administrators and programmers to secure different objects.
Each securable object maintains an access control list (ACL) that determines who can and cannot perform certain securable actions on an object. This ACL is the center of Windows 2000 access control, and is associated with a securable object in some combination of the following three ways:
Building and assigning ACLs for securable objects is the primary topic of this chapter.
Although I have explained which objects are securable, I have not yet discussed what it really means for an object to be securable. Windows provides a fine level of control over the actions that can be performed on securable objects. Securable actions are performed only if the requesting trustee has the proper access rights to the object. Table 10-2 describes the three groups of access rights that can apply to an object.
Table 10-2. Access rights, defined by the system, that can apply to an object
Access Type | Description |
---|---|
Standard rights | Standard rights apply to all object types in the system, and include rights such as the ability to delete an object or to read an object's security. For a list of all the standard rights defined by Windows 2000, see Table 10-13. |
Specific rights | Specific rights apply only to a specific type of securable object. For example, a specific right for a file object would be the right to append data or to read data from the file. |
Generic rights | Generic rights indicate a collection of standard and specific rights for an object. The system defines four generic rights: read, write, execute, and all. The meaning of each generic right differs from object to object. |
I will discuss each type of right in more detail throughout this chapter. At this time, however, it is important simply to think of a right as something that either allows or disallows a user to do something to an object. For example, a file might allow a user to read a file but disallow that same user to delete the file; this is possible because the system defines different rights for the reading of and deleting of a file.
When a user attempts to perform a securable task on an object, the system performs an access check. The access check searches the rights assigned to the object and compares them to the identity of the user attempting the action. If the system determines that the user has the requested access to the object, the action is performed. If the user does not have proper access, the action is not performed and the software running on the user's behalf receives an "Access Denied" error.
NOTE
The system also provides the ability to report on access attempts (successful and unsuccessful) made to securable objects. This is called auditing. Audit events are reported to the event log. Any access right that can be allowed or denied for an object can also be audited for that object. Although auditing is similar to access control, it is a separate and far less commonly used feature. Much of what you learn regarding access control will apply to auditing, so it might be helpful for you to be aware of the feature now. (I will discuss auditing in the section "Auditing and the SACL" later in this chapter.)
As I mentioned earlier, the security for each type of securable object in the system is largely stored and manipulated in the same manner as security for any other securable object. This is because all access control in Windows 2000 is implemented via a data structure called a security descriptor. The security descriptor maintains important security information for an object, such as its owner, and a list of rights associated with users of the system. Each securable object in Windows has a security descriptor. Figure 10-1 shows a representation of a security descriptor, and Table 10-3 describes the components. You'll find that you are most often concerned with the owner and discretionary access control list (DACL) components of the security descriptor.
Figure 10-1. The security descriptor
As I discussed, manipulating security for objects in Windows is pretty much the same process from one type to another. In a typical scenario, a security descriptor is created by your software and then passed to a system function that creates the object, which assigns the security to the object.
Table 10-3. Components of a security descriptor
Component | Description |
---|---|
Revision | A value indicating the revision level of the security descriptor structure. |
Control | A set of flags indicating the meaning of the contents of the security descriptor. |
Owner | The security identifier (SID) of the owner of the object. The owner of an object has special rights—the owner can always read and modify the security for the object regardless of whether he has explicitly assigned rights to do so as described in the DACL. All securable objects have an owner. (For a discussion on SIDs, see Chapter 9.) |
Group | The SID of the primary group of the object. Windows 2000 does not utilize the primary group in access control. The information is maintained so that Microsoft Windows NT can be used as a file-server platform for operating systems other than Windows. |
DACL | The discretionary access control list (DACL) is an access control list that describes all the access rights for an object. This list defines who can and cannot perform securable actions on an object. If a DACL is not present, everyone has all rights to the object. If a DACL is present but empty, no one but the owner has rights to the object. |
SACL | The system access control list (SACL) is a list of access rights associated with users for the purpose of auditing. The SACL does not affect access to an object, but it does cause access to an object to be reported to the event log. See the section "Auditing and the SACL" later in this chapter for more information. |
You can also retrieve a copy of the security descriptor of an existing object, use system functions to read or modify the security descriptor, and then use a system function to set the security descriptor of the original object.
NOTE
It might seem less efficient to use system functions to modify the security descriptor once you have retrieved a copy of it from the object. You might ask yourself why you would not access the data directly with your software—after all, you do have a copy of the data structure in your process's memory. Although you could access the data this way, it is important not to because the security descriptor is intended to be accessed as an "opaque" structure so that your code will function properly in future versions of Windows.
An ACL is little more than a sequential list of structures of variable lengths called access control entries, or ACEs. Each ACE indicates an access right and the SID of a trustee to which the right is associated for the object.
The DACL and the SACL are ACLs. The DACL is used for access control of an object; its ACEs indicate who is allowed or disallowed access to the object. The SACL is used for access auditing. The structure for the DACL and the SACL are the same, and the code to manipulate them is implemented similarly. I will discuss the SACL later in this chapter in the section "Auditing and the SACL," but much of our discussion here regarding the DACL applies to the SACL.
When an application attempts to access a secured object, the system scans the DACL of the object looking for ACEs, which indicate either the user trustee account under which the application is running or a group trustee account of which the user is a member. If a matching ACE is found, the system checks to see if the ACE grants or denies the right to perform the access requested by the application. The access check is discussed in more detail shortly, but first let's look at the six types of ACE. Table 10-4 describes them. The access-allowed ACE and the access-denied ACE are by far the most common.
NOTE
Object-type ACEs are not used with any securable objects in the system except the directory services objects. However, you can use object-type ACEs with your own private objects. I will focus mostly on the regular ACE types, but I will discuss object-type ACEs briefly throughout this chapter.
Table 10-4. ACE types in Windows 2000
ACE Type (value used by the system) | Description |
---|---|
Access allowed (ACCESS_ALLOWED_ACE_TYPE) | Defines a set of access rights allowed to a specified trustee account |
Access denied (ACCESS_DENIED_ACE_TYPE) | Defines a set of access rights denied to a specified trustee account |
System audit (SYSTEM_AUDIT_ACE_TYPE) | Defines a securable action that will cause an audit report if performed by the specified trustee account |
Access-allowed object (ACCESS_ALLOWED_OBJECT_ACE_TYPE) | Defines a single access right that is allowed for a specified trustee account for an object or an object's subobject or property (typically used with directory services objects) |
Access-denied object (ACCESS_DENIED_OBJECT_ACE_TYPE) | Defines a single access right that is denied for a specified trustee account for an object or an object's subobject or property (typically used with directory services objects) |
System audit object (SYSTEM_AUDIT_OBJECT_ACE_TYPE) | Defines a single access right that will cause an audit report if performed by a specified trustee account for an object or an object's subobject or property (typically used with directory services objects) |
Standard access-allowed ACEs and access-denied ACEs are pretty simple. Table 10-5 shows the contents of a standard ACE.
Table 10-5. Contents of a standard (nonobject) ACE
ACE Component | Description |
---|---|
ACE type | A numerical value indicating the ACE type. (Table 10-4 shows ACE types in Windows 2000.) |
ACE flags | Indicate inheritance rules for ACEs as well as auditing rules for ACEs in a SACL. (For a list of the available inheritance flags, see Table 10-11.) |
Access mask | A 32-bit value indicating the access rights described by the ACE. |
Trustee's SID | Indicates the trustee user, group, or computer account with which the access rights of the ACE are associated. |
Earlier in the chapter you learned about the three types of access rights defined by the system: standard, specific, and generic. The access mask portion of an ACE is a 32-bit value in which each possible access right for a given object is mapped to a bit.
NOTE
A single ACE can be used to indicate multiple access rights for a given trustee, because each access right maps to a single bit in the ACE's access map.
The access mask is divided into sections for each of the three types of access rights supported by Windows. Figure 10-2 shows the bits and their purposes.
Figure 10-2. Access mask format
ACEs for system and private objects that exist in a hierarchy of parent/child relationships can indicate inheritance rules. I will cover inheritance in more detail when we begin our discussion on programmatically manipulating ACLs; however, it is useful to know now what types of inheritance are allowed. The following list explains the possibilities:
Each of these decisions can be made for an ACE irrespective of the other inheritance properties of the ACE, so as you can see, an ACE can be made inheritable in a number of different ways.
NOTE
It is also possible to create an object whose security descriptor does not allow ACEs to inherit from parents. Such a descriptor is called a protected security descriptor. It stops inheritance to the object as well as to children of the object. It does not, however, affect the security descriptor of the parent object or any of the other children of the parent.The system keeps track of which ACEs are inherited and which are explicitly set to an object. This way, if a security descriptor is set protected after the object is created, the system knows which ACEs to remove from the DACL and SACL. ACEs that are explicitly set to an object take precedence over ACEs that are inherited.
You now have a good idea of how the security for a securable object is maintained. We will soon be ready to begin our discussion of the security API, but first it is important that you understand access checks.
When you log on to a system running Windows 2000, you enter your username and password. The system looks up your user account and the group trustee accounts of which you are a member, and stores each trustee account's SID in an internal structure called a token. The system also stores a list of privileges that are assigned to your trustee and group trustee accounts. You'll learn more about tokens in Chapter 11, but for now you should think of the token as the structure that stores your identity and privileges.
After the system builds a token for you and launches the shell process, it associates your token with the shell. From this point forward, any process that the shell process launches automatically inherits a copy of your token. This is how the system maintains a sense of your identity.
Processes that are associated with your token are said to be running in your user context or security context. When a process running in your security context attempts to perform a securable action on a securable object, the system first performs an access check to determine whether you or one of your groups has sufficient rights to perform the task. Figure 10-3 shows the relationship of the entities involved in an access check.
Figure 10-3. A process accessing a securable object
NOTE
It is also possible for a thread in a process to run in a user context different from the process. This is called impersonation and is covered in detail in the next chapter.
Here are the steps the system takes when it performs an access check:
NOTE
You can create a token that is restricted to the access rights of additional, arbitrarily selected trustee accounts. This is called a restricted token. If your process or thread is associated with a restricted token, the rules of an access check change. This topic is covered in detail in Chapter 11.
The most important steps in this process are steps 4, 6, 8, and 9. In step 4, if the system finds that the object's security descriptor does not include a DACL, the access check succeeds for everyone. In step 6, an access check fails if an access-denied ACE matches your user or group SIDs and any of the access rights for the access check. It fails immediately regardless of whether a later ACE in the DACL would have passed the access check. Step 8 passes the access check after all of the requested rights are found, regardless of whether an access-denied ACE later in the DACL would have failed the access check. And finally, in step 9, not enough ACEs to pass a check indicates implicit failure.
As you can see, in an access check, the order of ACEs in a DACL is very important. You should always place access-denied ACEs before access-allowed ACEs in a DACL. The Windows 2000 user interface enforces ACE ordering; however, in your own software, you can place ACEs in any order. If you place an access-denied ACE after an access-allowed ACE in your object's DACL, you should have a good reason!
NOTE
An access-denied ACE at the end of a DACL is a wasted ACE. If the ACE denies access that was already allowed, the access check would never even see the denied ACE at the end. And if the ACE denies access that was not explicitly allowed, it was not necessary to deny the access in the first place—access is implicitly denied unless it is explicitly allowed.
Microsoft has published a preferred order of ACEs in a DACL. It is referred to as a "preferred" order because it is not completely enforced. Table 10-6 shows the preferred ordering of ACEs in a DACL.
Table 10-6. Preferred ordering of ACEs in a DACL
ACE Type | Group |
---|---|
Access-denied ACEs Access-denied object ACEs that apply to subobjects or properties of the object Access-allowed ACEs Access-allowed object ACEs that apply to subobjects or properties of the object | Explicitly assigned (noninherited) ACEs |
Access-denied ACEs Access-denied object ACEs that apply to subobjects or properties of the object Access-allowed ACEs Access-allowed object ACEs that apply to subobjects or properties of the object | Inherited ACEs |
The ordering rule in Table 10-6 might look complex, but remember that object ACEs are not used for any securable object in the system except directory services objects (objects in Active Directory). Ignoring object ACEs will simplify the order of ACEs dramatically.
I have discussed system securable objects, the structure of the security descriptor that secures the object, and how the system uses the DACL to check security against a request made by software. However, I have not yet explained how your software can create secure objects that use the Windows security model. Windows refers to this ability as securing private objects.
Private object security is a very powerful and flexible feature included in Windows. Later in this chapter I discuss the security API used with private objects. At this point, I would like to explain how private object security ties in to the existing security model in Windows.
Everything you have learned about security descriptors, ACLs, DACLs, and ACEs also applies to private objects, except that your software, rather than the system, must decide which of the standard rights (listed in Table 10-13) apply to your objects. Additionally, you must define specific rights for your objects, and map the four generic rights to appropriate combinations of standard and specific rights.
Your software performs the access check by calling a system function. Typically, your software is a service that passes the token of a connected client to the system along with a security descriptor. The system then indicates whether the required access rights exist for the client. Your service is responsible for performing or refusing to perform the requested action, based on the results of the access check.
The system creates and destroys security descriptors in memory for your private objects. You must associate the security descriptors with the data that they protect. Your service is also responsible for storing the security with the data in persistent storage when your service ends (if the objects persist, that is).
NOTE
Private object security does not automatically secure the data of the objects defined by your software—if your objects are stored in files, you must still secure the files. Private object security does, however, provide a mechanism for allowing you to control your data at a fine level of granularity, without being limited to file security or the security of some other storage mechanism in Windows.
To become a successful security developer, it is important to understand and also be comfortable with security in Windows 2000. Spending some time modifying the security of system objects via the user interface will greatly increase your ability to effectively design software that incorporates security.
The following sections walk you through the tools supplied with Windows to help you become familiar with security. In Windows, registry keys are securable and files and directories (on NTFS partitions only) are securable. The file system is probably the most effective way to become familiar with security, because its inheritance model includes both container objects (directories) and non-container objects (files). If you do not have an NTFS partition with which to meddle, the registry will also do just fine.
These steps describe how security options can be specified in the registry:
Figure 10-4. The registry editor (RegEdt32.exe)
Figure 10-5. Setting inheritable permissions for ANewKey
Here are some examples that illustrate how permissions work for files on an NTFS partition:
Figure 10-6. Setting permissions for a file on an NTFS partition
I strongly suggest you spend more time experimenting with permissions of registry keys or files (if you have an NTFS partition). Exploring will work wonders for your abilities as a security programmer.
If you are new to security programming in Windows, you have just been bombarded with new terms and ideas. So now is a good time for us to rehash what we have covered before we dive into the depths of the security API.