Windows NT Security
Jim FrostMay 4, 1995
Table Of Contents
Why security is important for the average user
In part because of the "personal" nature of personal computers, most computer users do not believe they
want or need security. In truth, there are many ways in which security is useful even to the home or individual user.
While most people believe that security is only used for denying other people access to your files,
it has a far more important purpose -- to keep you or others from accidentally or deliberately destroying something important.
For example, almost everyone has accidentally deleted all the files in the current directory only to
find that they were not in the directory they expected. Security makes it possible (although not mandatory) to protect critical
files from accidental deletion in this manner.
Another use for security mechanisms becomes obvious when a single computer is shared between several
users (a very common occurrence in business environments, and almost universal in home environments). While most often it
is acceptable for users to look at the contents of each others' files, you probably don't want your son, daughter, or roommate
to accidentally delete your term project when they meant to delete their letter to mom.
But possibly the most important potential use for security on personal computer systems is protection
from malice. Few would argue that the scourge of personal computers is the virus, yet most viruses can be stopped cold with
even the most primitive security features. By disallowing changes to system files and executables by normal users a virus
that is not run by an administrator cannot possibly invade the system. This is, in part, why viruses are unheard-of on UNIX
systems -- a virus complicated enough to overcome the system security is big enough to be noticed immediately and so difficult
to write that few will even attempt the effort.
Security objects
Windows NT's security is based on just five security objects which are used to identify and subclass users,
indicate permissable operations, and relate ownership and permissions to system objects.
The security objects are:
- The Security Identifier (SID)
- The Access Control Entry (ACE)
- The Access Control List (ACL)
- The Security Descriptor
- The Access Token
Each of these objects builds upon the others
in order to provide certain security features.
The Security Identifier
The most basic security object in Windows NT is the security identifier, or SID.
An SID is a unique identifier used to identify a user or group of users that exist on a particular computer or in a particular
domain (group of computers):
Security Identifier
| Account |
| Domain |
NT provides two API calls that can be used to map between SIDs and user and group names. They are:
| Function |
Description |
LookupAccountName() |
Given an account name, find its SID. |
LookupSidAccount()
| Given an SID, find the account name and its domain. |
The Access Control Entry
An Access Control Entry, or ACE, is the most basic unit of permission in NT. ACEs come in two types, access
allowed and access denied, which are used to grant or refuse access respectively(1).
An ACE contains an SID which indicates which user or group of users the permission applies to, and
a permission mask that indicates exactly what kind of permission is being granted or refused.
Access Control Entry
| Type |
| Security Identifier |
| Permissions Mask |
The permission mask is broken into parts which indicate permissions specific to a particular object
type (called specific rights) and generic permissions (generic rights) that apply to all objects.
The standard rights, which control the accessibility and exclusivity for all objects, are:
| Right |
Description |
DELETE |
The ability to delete the object. |
READ_CONTROL |
The ability to inspect the object's security information. |
WRITE_DAC |
The ability to change the object's list of permissions. |
WRITE_OWNER |
The ability to change the owner of the object |
SYNCHRONIZE |
Force mutual-exclusion of object accesses. |
While each object type has its own list of specific rights, the filesystem rights are the most frequently
encountered. They are:
| Right |
Description |
FILE_READ_DATA |
The ability to read the file. |
FILE_LIST_DIRECTORY |
The ability to list the contents of a directory. |
FILE_WRITE_DATA |
The ability to modify the file's data. |
FILE_ADD_FILE |
The ability to add a new file to a directory. |
FILE_APPEND_DATA |
The ability to append data to a file. |
FILE_ADD_SUBDIRECTORY |
The ability to add a subdirectory to a directory. |
FILE_READ_EA |
The ability to read the extended attributes(2) of a file. |
FILE_WRITE_EA |
The ability to change the extended attributes of a file. |
FILE_EXECUTE |
The ability to run an executable. |
FILE_TRAVERSE |
The ability to open a file or run an executable within a directory. |
FILE_DELETE_CHILD |
The ability to delete a file or directory within a directory.
|
FILE_READ_ATTRIBUTES |
The ability to read a file's attributes (e.g. system or hidden). |
FILE_WRITE_ATTRIBUTES |
The ability to change a file's attributes. |
The Access Control List
While an ACE is the basic unit of permission on NT, a single ACE is seldom enough to fully describe the
accessibility of an object to different users or groups on the system.
Consider, for example, a source code file. You need to be able to manipulate your source files in any
way you like -- read them, modify them, delete them, etc. You would also like the members in your development group to be
able to look at your source files, but not to change them since everyone else in your group is an incompetant dweeb who can
barely understand your code, much less change it in any useful way. Lastly, you would like to keep your manager from even
looking at your code lest he find out that you spent last week playing DOOM rather than working.
To maintain multiple privilege levels for different users or groups of users in this way, ACEs are
grouped into Access Control Lists, or ACLs. Simply put, an ACL describes all of the users and groups who are either allowed
or denied some sort of access to a particular object.
Access Control List
| ACE |
| ACE |
| ACE |
| ... |
When a thread requests access to an object (by opening a file, for instance), the system performs two
passes over the ACL.
In the first pass the system inspects every "access denied" ACE in the list. If it finds an SID that
matches the thread's SID, or an SID of a group that the thread's owner is a member of, access is immediately denied.
Once all "access denied" ACEs have been inspected the system proceeds to check all "access allowed"
ACEs. For each matching ACE, the permission mask in the ACE is added to a growing list of permissions granted to the thread's
SID for access to the object. Once the list of permissions matches or exceeds the group of permissions that was requested
permission is granted. If the end of the ACL is reached before enough permissions are accumulated access is denied.
NT provides a number of functions for managing ACLs:
| Function |
Description |
AddAce() |
Add a new ACE to the access control list. |
DeleteACE() |
Remove an ACE from the access control list. |
InitializeAcl() |
Create a new ACL structure. |
IsValidAcl() |
Determine validity of an ACL structure. |
GetAclInformation() |
Retrieve information about the ACL. |
SetAclInformation() |
Set the ACL revision information. |
Even with these functions the variable-length nature inherent in ACLs makes them tedious to deal with.
The Security Descriptor
While an ACL describes the accessibility of an object, it does not completely describe the security attributes
of an object. The complete group of security attributes is kept in an object called a security descriptor, which
contains:
| Object |
Description |
| The owner SID |
The SID of the user who owns this object |
| The object's primary group SID |
The group of users to which this object belongs |
| The system ACL |
The access control list used for auditing features |
| The discretionary ACL |
The access control list that specifies which users or groups may access an object. |
When you want to view or change the security attributes of an object, you must do so through the object's
security descriptor.
The following functions are used to manage the security descriptor:
| Function |
Description |
IsValidSecurityDescriptor() |
Determine the validity of a security descriptor |
InitializeSecurityDescriptor() |
Create a new security descriptor |
GetSecurityDescriptorControl() |
Retrieve control information about the security descriptor |
GetSecurityDescriptorDacl() |
Retrieve the security descriptor's discretionary ACL |
SetSecurityDescriptorDacl() |
Change the security descriptor's discretionary ACL |
GetSecurityDescriptorGroup() |
Retrieve the security descriptor's primary group |
SetSecurityDescriptorGroup() |
Change the security descriptor's primary group |
GetSecurityDescriptorOwner() |
Retrieve the owner from the security descriptor |
SetSecurityDescriptorOwner() |
Change the owner in the security descriptor |
GetSecurityDescriptorSacl(); |
Retrieve the security descriptor's system ACL |
SetSecurityDescriptorSacl(); |
Change the security descriptor's system ACL |
The Access Token
An access token is essentially NT's identification card for a user. Every process, and potentially
every thread, has a related access token which identifies the user account that the process is running under and a lot of
default values to be used when creating new objects.
An access token contains a lot of security information about the user, including their SID, their primary
group SID, their current privilege set, the SIDs that should be used to indicate the owner and group of new objects and files,
and the default discretionary ACL used when creating new objects and files.
Access tokens are created through login services (e.g. the login dialog or a network share login),
through impersonation (temporary assumption of a user's security attributes by a service's thread), or through the NT login
API(3,4).
C++ Classes For Manipulating NT Security
While the concepts behind NT's security are fairly simple, the variable size of the data structures makes
management tedious at best and therefore is a prime target for encapsulation. The accompanying C++ classes (which should be
self-explanatory) attempt to simplify the interface by providing a straighforward interface to the relevant objects.
Example Applications
The WHOAMI Program
The simplest of the sample applications is WHOAMI, which finds the current user's SID and translates it
into the related domain and account name through the use of the SecurityIdentifier class.
The ACCESS Program
The ACCESS program is useful for inspecting the security information of NTFS(5) files. Users familiar with the Security functionality of the NT File Manager will notice that ACCESS
shows considerably more information about the security attributes of the file than is shown (or even possible to manipulate)
using the File Manager. While the File Manager's security management is flexible, it actually supports only a small subset
of the security functionality available in NT. ACCESS demonstrates the use of the SecurityDescriptor, AccessControlList,
and AccessControlEntry objects for querying the security information of a filesystem object.
The RESTRICT Program
To demonstrate the modification of a file's discretionary ACL, the RESTRICT program builds an ACL that
permits read-only access to the indicated files by all but the owner of the file. This is conceptually similar to the ATTRIB
-R command found in MS-DOS, but shows the additional flexibility of NT's security subsystem. RESTRICT demonstrates the use
of the AccessControlList class to build a new ACL.
The PROTECT Program
As mentioned at the beginning of this document, it's possible to harden your system against viruses through
the use of security mechanisms. The PROTECT program, when run by an administrator, changes the owner and permissions of all
executable files in such a way as to make it difficult or impossible for a virus to alter executables. Provided that users
normally work without administrator privileges a system protected in this manner should be relatively invulnerable to infection.
Footnotes
(1) Actually there are two more ACE types: system audit, used for generating logs of accesses; and
system alarm, which is not yet implemented.
(2) As with the Macintosh, NTFS provides multiple data streams in each file which are useful for storing
additional file information such as icons. Extended attributes refers to all of the data streams except for the default
(normal file data) stream.
(3) This API was not publicly available prior to NT 3.51.
(4) Since the access token API is new, and is not yet on my system, no class is provided for managing access
tokens.
(5) NTFS is the only filesystem currently supported by NT which implements security.