NT securityThe setting of POSIX like object permissions is controlled by the
mount option (no)acl
which is set to acl by default. The design goal
is to utilize the Windows access control API to implement real POSIX
permissions.We start with a short overview. Note that this overview must
be necessarily short. If you want to learn more about the Windows security
model, see the Access Control article in MSDN documentation.NT securityIn the NT security model, almost any "object" is securable.
"Objects" are files, processes, threads, semaphores, etc.Every object has a data structure called "security descriptor" (SD)
attached. The SD contains all information necessary to control who can
how access an object. The SD of an object consists of five parts:Flags which control several aspects of this SD. This is
not discussed here.The SID of the object owner.The SID of the object owner group.A list of "Access Control Entries" (ACE), called the
"Discretionary Access Control List" (DACL).Another list of ACEs, called the
"Security Access Control List" (SACL), which doesn't matter for our
purpose.Every ACE contains a so-called "Security IDentifier" (SID) and
other stuff which is explained a bit later. Let's talk about the SID first.
A SID is a unique identifier for users, groups, computers and AD
domains. SIDs are basically comparable to POSIX UIDs and GIDs, but are
more complicated because they are unique across multiple machines or
domains. A SID is a structure of multiple numerical values. There's
a convenient convention to type SIDs. Here's an example:SID of a machine "foo":
S-1-5-21-165875785-1005667432-441284377
SID of a user "johndoe" of the system "foo":
S-1-5-21-165875785-1005667432-441284377-1023
The leading "S" has no further meaning except to show that this is
a SID. The next number is a version number which is always 1 so far.
The next two numbers are the authority which shows the initiated what
kind of SID this is. There are a couple of builtin accounts and
accounts with very special meaning. However, computer and domain SIDs
always start with "S-1-5-21". The next three numbers, all 32 bit values,
are the unique 96 bit identifier of the comupter system. This is
hopefully unique all over the world, but in practice it's sufficient if
the comuter SIDs are unique within a single Windows network.As you can see in the above example, SIDs of users (and groups)
are identical to the computer SID, except for an additional part, the
so-called "relative identifier" (RID). So the SID of a user is always
uniquely attached to the system on which the account has been generated.It's a bit different in domains. The domain has its own SID, and
that SID is identical to the SID of the first domain controller, on
which the domain is created. Domain user SIDs look exactly like the
computer user SIDs, the leading part is just the domain SID and the RID
is created when the user is created.Ok, consider you created a new domain "bar" on some new domain
controller and you would like to create a domain account "johndoe":SID of a domain "bar.local":
S-1-5-21-186985262-1144665072-740312968
SID of a user "johndoe" in the domain "bar.local":
S-1-5-21-186985262-1144665072-740312968-1207
Ok, so you now have two accounts called johndoe, one account
created on the machine "foo", one created in the domain "bar.local".
Both have different SIDs and not even the RID is the same. How do
the systems know it's the same account? After all, the name is
the same, right? The answer is, these accounts are NOT identical.
For all the machines know there are two different accounts, one is
"FOO\johndoe", the other one is "BAR\johndoe" or "johndoe@bar.local".
Different SID, different account. Full stop.
The last part of the SID, the so called "Relative IDentifier" (RID),
is by default used as UID and/or GID under Cygwin when you create the
/etc/passwd and /etc/group
files using the mkpasswd and mkgroup
tools. Domain account UIDs and GIDs are offset by 10000 by default
which might be a bit low for very big organizations. Fortunately there's
an option in both tools to change the offset...Do you still remember the SIDs with special meaning? In offical
notation they are called "well-known SIDs". For example, POSIX has no GID
for the group of "all users" or "world" or "others". The last three rwx
bits in a permission value just represent the permissions for "everyone
who is not the owner or is member of the owning group". Windows has a
SID for these poor souls, the "Everyone" SID. Other well-known SIDs
represent more circumstances instead of actual users or groups. Here
are a few examples for well-known SIDs:
Everyone S-1-1-0 Simply everyone...
Batch S-1-5-3 Processes started via the task
scheduler are member of this group.
Interactive S-1-5-4 Only processes of users which are
logged in via an interactive
session are members here.
Authenticated Users S-1-5-11 Users which have gone through
the authentication process and
survived. Anonymously accessing
users are not incuded here.
SYSTEM S-1-5-18 A special account which has all
kinds of dangerous rights, sort of
an uber-root account.
For a full list please refer to
Well-known SIDs.
Naturally well-known SIDs are the same on each machine, so they are
not unique to a machine or domain. They have the same meaning across
the Windows network.Additionally there are a couple of well-known builtin groups,
which have the same SID on every machine and which have certain user
rights by default:
administrators S-1-5-32-544
users S-1-5-32-545
guests S-1-5-32-546
...
For instance, every account is usually member in the "Users"
group. All administrator accounts are member of the "Administrators"
group. That's all about it as far as single machines are involved. In
a domain environment it's a bit more tricky. Since these SIDs are not
unique to a machine, every domain user and every domain group can be a
member of these well known groups. Consider the domain group "Domain
Admins". This group is by default in the "Administrators" group. Let's
assume the above computer called "foo" is a member machine of the domain
"bar.local". If you stick the user "BAR\johndoe" into the group "Domain
Admins", this guy will automatically be a mamber of the administrators
group on "foo", when logging in on "foo". Neat, isn't it?Back to ACE and ACL. POSIX is able to create three different
permissions, the permissions for the owner, for the group and for the
world. In contrast the Windows ACL has a potentially infinite number of
members... as long as they fit into 64K. Every member is an ACE.
ACE consist of three parts:The type of the ACE (allow ACE or deny ACE).Permission bits, 32 of them.The SID for which the permissions are allowed or denied.The two (for us) important types of ACEs are the "access allowed
ACE" and the "access denied ACE". As the names imply, the allow ACE
tells the system to allow the given permissions to the SID, the deny ACE
results in denying the specific permission bits.The possible permissions on objects are more detailed than in
POSIX. For example, the permission to delete an object is different
from the permission to change object data, and even changing object data
can be separated into different permission bits for different kind of
data.File permissionsOn NTFS and if the noacl mount option is not
specified for a mount point, Cygwin sets file permissions as in POSIX.
Basically this is done by defining a SD with the matching owner and group
SIDs, and a DACL which contains ACEs for the owner, the group and for
"Everyone", which represents what POSIX calls "others".To use NT security correctly, Cygwin depends on the files
/etc/passwd and /etc/group.
These files define the traslation between the Cygwin uid/gid and the
Windows SID. The SID is stored in the pw_gecos field in
/etc/passwd, and in the gr_passwd field in
/etc/group. Since the pw_gecos field can contain
more information than just a SID, there are some rules for the layout.
It's required that the SID is the last entry of the pw_gecos field,
assuming that the entries in pw_gecos are comma-separated. The
commands mkpasswd and mkgroup
usually do this for you.Another interesting entry in the pw_gecos field (which is also
usually created by running mkpasswd) is the Windows user
name entry. It takes the form "U-domain\username" and is typically used
by services to authenticate a user. Logging in through ssh
or telnet are two typical scenarios.
A typical snippet from /etc/passwd:/etc/passwd:
SYSTEM:*:18:544:,S-1-5-18::
Administrators:*:544:544:,S-1-5-32-544::
Administrator:unused:500:513:U-FOO\Administrator,S-1-5-21-790525478-115176313-839522115-500:/home/Administrator:/bin/bash
corinna:unused:11001:11125:U-BAR\corinna,S-1-5-21-2913048732-1697188782-3448811101-1001:/home/corinna:/bin/tcsh
The SYSTEM entry is usually needed by services. The Administrators
entry (Huh? A group in /etc/passwd?) is only here to allow
ls to print some file ownerships correctly. Windows
doesn't care if the owner of a file is a user or a group. In older
versions of Windows NT the default ownership for files created by an
administrator account was set to the group Administrators instead of to
the creating user account. This has changed, but for those older
systems it's convenient to have the Administrators group in
/etc/passwd.The really interesting entries are the next two. The Administrator
entry is for the local administrator, the corinna entry matches the corinna
account in the domain BAR. The information given in the pw_gecos field
are all we need to exactly identify an account, and to have a two way
translation, from Windows account name/SID to Cygwin account name uid and
vice versa. Having this complete information allows us to choose a Cygwin
name and uid which doesn't have to match the Windows account at all. As
long as the pw_gecos information is available, we're on the safe side:/etc/passwd, tweaked:
root:unused:0:513:U-FOO\Administrator,S-1-5-21-790525478-115176313-839522115-500:/home/Administrator:/bin/bash
thursday_next:unused:11001:11125:U-BAR\corinna,S-1-5-21-2913048732-1697188782-3448811101-1001:/home/corinna:/bin/tcsh
The above /etc/passwd will still work fine.
You can now login via ssh as the user "root", and
Cygwin dutyfully translates "root" into the Windows user
"FOO\Administrators" and files owned by FOO\Administrators are shown to
have the uid 0 when calling ls -ln. All you do you're
actually doing as Administrator. Files created as root will be owned by
FOO\Administrator. And the domain user BAR\corinna can now happily
pretend to be Thursday Next, but will wake up sooner or later finding
out she's still actually the domain user BAR\corinna...Do I have to mention that you can also rename groups in
/etc/group? As long as the SID is present and correct,
all is well. This allows for instance to rename the "Administrators" group
to "root" as well:/etc/group, tweaked:
root:S-1-5-32-544:544:
Last but not least you can also change the primary group of a user
in /etc/passwd. The only requirement is that the user
is actually a member of the new primary group in Windows. For instance,
normal users in a domain environment are members in the group "Domain Users",
which in turn is member of the well-known group "Users". Additionally let's
assume the user is also a member of the newly created group . The default
primary group for users is
As you can see, I changed my primary group membership from 513 (None)
to 547 (powerusers). So all files I created inside of Cygwin were now owned
by the powerusers group instead of None. This is the way I liked it.Groups may be mentioned in the passwd file, too. This has two
advantages:Because NT assigns them to files as owners, a
ls -l is often more readable.Moreover it's possible to assigned them to files as
owners with Cygwin's chown.The group `system' is the aforementioned synonym for the operating system
itself and is normally the owner of processes that are started through
service manager. The same is true for files that are created by
processes, which are started through service manager.NT SIDs in CygwinThis has the following advantages:ntsec works better in domain environments.Accounts (users and groups) may get another name in
Cygwin than their NT account name. The name in /etc/passwd
or /etc/group is transparently used by Cygwin
applications (e.g. chown, chmod,
ls):
root::500:513::/home/root:/bin/sh
instead of
adminstrator::500:513::/home/root:/bin/sh
Caution: If you like to use the account as login account via
telnet etc. you have to remain the name unchanged or
you have to use the special version of login which is
part of the standard Cygwin distribution since 1.1.Cygwin UIDs and GIDs are now not necessarily the RID
part of the NT SID:
root::0:513:S-1-5-21-54355234-56236534-345635656-500:/home/root:/bin/sh
instead of
root::500:513::/home/root:/bin/sh
As in U*X systems UIDs and GIDs numbering scheme now
don't influence each other. So it's possible to have same Id's for a
user and a group:/etc/passwd:
root::0:0:S-1-5-21-54355234-56236534-345635656-500:/home/root:/bin/sh
/etc/group:
root:S-1-5-32-544:0:
The tools mkpasswd and mkgroup
create the needed entries by default. If you don't want that you can use
the options -s or --no-sids. I suggest
not to do this since ntsec works better when having the SIDs available.Please note that the pw_gecos field in /etc/passwd
is defined as a comma separated list. The SID has to be the last field!
the_king::1:1:Elvis Presley,U-STILLHERE\elvis,S-1-5-21-1234-5678-9012-1000:/bin/sh
For a local user just drop the domain:
the_king::1:1:Elvis Presley,U-elvis,S-1-5-21-1234-5678-9012-1000:/bin/sh
In either case the password of the user is taken from the NT user
database, NOT from the passwd file!As in the previous chapter I give my personal
/etc/passwd and /etc/group as
examples. Please note that I've changed these files heavily! There's no
need to change them that way, it's just for testing purposes and...
for fun./etc/passwd
root:*:0:0:Administrators group,S-1-5-32-544::
SYSTEM:*:18:18:,S-1-5-18:/home/system:/bin/bash
admin:*:500:513:,S-1-5-21-1844237615-436374069-1060284298-500:/home/Administrator:/bin/bash
corinna:*:100:0:Corinna Vinschen,S-1-5-21-1844237615-436374069-1060284298-1003:/home/corinna:/bin/tcsh
Guest:*:501:546:,S-1-5-21-1844237615-436374069-1060284298-501:/home/Guest:/bin/bash
/etc/group
root:S-1-5-32-544:0:
local:S-1-2-0:2:
network:S-1-5-2:3:
interactive:S-1-5-4:4:
authenticatedusers:S-1-5-11:5:
SYSTEM:S-1-5-18:18:
local_svc:S-1-5-19:19:
netwrk_svc:S-1-5-20:20:
none:S-1-5-21-1844237615-436374069-1060284298-513:513:
bckup_op:S-1-5-32-551:551:
guests:S-1-5-32-546:546:
pwrusers:S-1-5-32-547:547:
replicator:S-1-5-32-552:552:
users:S-1-5-32-545:545:
If you want to do similar changes to your files, please do that only
if you're feeling comfortably with the concepts. Otherwise don't be surprised
if some stuff doesn't work anymore. If you screwed up things, revert to files
created by mkpasswd and mkgroup. Especially don't change the UID or the name
of user SYSTEM. Even if that works mostly, some Cygwin applications running
as local service under that account could suddenly start behaving strangely.
The mapping leakNow its time to point out the leak in the NT permissions.
The official documentation explains in short the following:access allow ACEs are accumulated regarding to the
group membership of the caller.The order of ACEs is important. The system reads them
in sequence until either any needed right is denied or all needed rights
are granted. Later ACEs are then not taken into account.All access denied ACEs _should_ precede any
access allowed ACE.Note that the last rule is a preference, not a law. NT will correctly
deal with the ACL regardless of the sequence order. The second rule is
not modified to get the ACEs in the preferred order.Unfortunately the security tab of the NT4 explorer is completely
unable to deal with access denied ACEs while the explorer of W2K rearranges
the order of the ACEs before you can read them. Thank God, the sort order
remains unchanged if one presses the Cancel button.You still ask "Where is the leak?" NT ACLs are unable to reflect each
possible combination of POSIX permissions. Example:
rw-r-xrw-
1st try:
UserAllow: 110
GroupAllow: 101
OthersAllow: 110
Hmm, because of the accumulation of allow rights the user may
execute because the group may execute.2st try:
UserDeny: 001
GroupAllow: 101
OthersAllow: 110
Now the user may read and write but not execute. Better? No!
Unfortunately the group may write now because others may write.3rd try:
UserDeny: 001
GroupDeny: 010
GroupAllow: 001
OthersAllow: 110
Now the group may not write as intended but unfortunately the user may
not write anymore, either. How should this problem be solved? According to
the official rules a UserAllow has to follow the GroupDeny but it's
easy to see that this can never be solved that way.The only chance:
UserDeny: 001
UserAllow: 010
GroupDeny: 010
GroupAllow: 001
OthersAllow: 110
Again: This works for both, NT4 and W2K. Only the GUIs aren't
able to deal with that order.The ACL APIFor dealing with ACLs Cygwin now has the ACL API as it's
implemented in newer versions of Solaris. The new data structure
for a single ACL entry (ACE in NT terminology) is defined in
sys/acl.h as:
typedef struct acl {
int a_type; /* entry type */
uid_t a_id; /* UID | GID */
mode_t a_perm; /* permissions */
} aclent_t;
The a_perm member of the aclent_t type contains only the bits
for read, write and execute as in the file mode. If e.g. read permission
is granted, all read bits (S_IRUSR, S_IRGRP, S_IROTH) are set.
CLASS_OBJ or MASK ACL entries are not fully implemented yet.The new API calls are
acl(2), facl(2)
aclcheck(3),
aclsort(3),
acltomode(3), aclfrommode(3),
acltopbits(3), aclfrompbits(3),
acltotext(3), aclfromtext(3)
Like in Solaris, Cygwin has two new commands for working with
ACLs on the command line: getfacl and
setfacl.Online man pages for the aforementioned commands and API calls can be
found on http://docs.sun.comNew setuid conceptPOSIX applications which have to switch the user context are using
the setuid and seteuid calls which
are not part of the Windows API.
Nevertheless these calls are supported under Windows NT/W2K since Cygwin
release 1.1.3. Because of the nature of NT security an application which
needs the ability has to be patched, though.NT uses so-called `access tokens' to identify a user and it's
permissions. To switch the user context the application has to request
such an `access token'. This is typically done by calling the NT API
function LogonUser. The access token is returned and
either used in ImpersonateLoggedOnUser to change user
context of the current process or in CreateProcessAsUser
to change user context of a spawned child process. An important restriction
is that the application using LogonUser must have special
permissions:
"Act as part of the operating system"
"Replace process level token"
"Increase quotas"
Note that administrators do not have all these user rights set
by default.Two new Cygwin calls are introduced to support porting
setuid applications with a minimum of effort. You only
give Cygwin the right access token and then you can call
seteuid or setuid as usual in POSIX
applications. The call to sexec is not needed
anymore. Porting a setuid application is illustrated by
a short example:
#include
/* Use the following define to determine the Windows version */
#define is_winnt (GetVersion() < 0x80000000)
#endif
[...]
struct passwd *user_pwd_entry = getpwnam (username);
char *cleartext_password = getpass ("Password:");
[...]
#ifdef __CYGWIN__
/* Patch the typical password test. */
if (is_winnt)
{
HANDLE token;
/* Try to get the access token from NT. */
token = cygwin_logon_user (user_pwd_entry, cleartext_password);
if (token == INVALID_HANDLE_VALUE)
error_exit;
/* Inform Cygwin about the new impersonation token.
Cygwin is able now, to switch to that user context by
setuid or seteuid calls. */
cygwin_set_impersonation_token (token);
}
else
#endif /* CYGWIN */
/* Use standard method for W9X as well. */
hashed_password = crypt (cleartext_password, salt);
if (!user_pwd_entry ||
strcmp (hashed_password, user_pwd_entry->pw_password))
error_exit;
[...]
/* Everything else remains the same! */
setegid (user_pwd_entry->pw_gid);
seteuid (user_pwd_entry->pw_uid);
execl ("/bin/sh", ...);
]]>
The new Cygwin call to retrieve an access token is defined as follows:
#include <windows.h>
#include <sys/cygwin.h>
HANDLE
cygwin_logon_user (struct passwd *pw, const char *cleartext_password)
You can call that function as often as you want for different user
logons and remember the access tokens for further calls to the second function.
#include <windows.h>
#include <sys/cygwin.h>
void
cygwin_set_impersonation_token (HANDLE hToken);
is the call to inform Cygwin about the user context to which further
calls to setuid/seteuid should switch to.
While you always need the correct access token to do a
setuid/seteuid to another user's context,
you are always able to use setuid/seteuid
to return to your own user context by giving your own uid as parameter.If you have remembered several access tokens from calls to
cygwin_logon_user you can switch to different user
contexts by observing the following order:
cygwin_set_impersonation_token (user1_token);
seteuid (user1_uid);
[...]
seteuid (own_uid);
cygwin_set_impersonation_token (user2_token);
seteuid (user2_uid);
[...]
seteuid (own_uid);
cygwin_set_impersonation_token (user1_token);
seteuid (user1_uid);
etc.
Switching User
Context
Since Cygwin release 1.3.3, applications that are members of the
Administrators group and have the Create a token
object, Replace a process level token and
Increase Quota user rights can switch user
context without giving a password by just calling the usual
setuid, seteuid,
setgid and setegid functions.
On NT and Windows 2000 the SYSTEM user has these privileges and can
run services such as sshd. However, on Windows 2003
SYSTEM lacks the
Create a token object right, so it is necessary to
create a special user with all the necessary rights, as
well as Logon as a service, to run such services.
For security reasons this user should be denied the rights to logon
interactively or over the network. All this is done by configuration
scripts such as ssh-host-config.
An important restriction of this method is that a process started
without a password cannot access network shares which require
authentication. This also applies to subprocesses which switched user
context without a password. Therefore, when using
ssh or rsh without a password, it
is typically not possible to access network drives.
Special values of user and group
ids
If the current user is not present in /etc/passwd,
that user's user id is set to a special value of 400. The user name for
the current user will always be shown correctly. If another user
(or a Windows group, treated as a user) is not present in
/etc/passwd, the user id of that user will have a
special value of -1 (which would be shown by ls as
65535). The user name shown in this case will be '????????'.
If the current user is not present in /etc/passwd,
that user's login group id is set to a special value of 401. If another
user is not present in /etc/passwd, that user's login
group id is set to a special value of -1. If the user is present in
/etc/passwd, but that user's group is not in
/etc/group and is not the login group of that user,
the group id is set to a special value of -1. The name of this group
(id -1) will be shown as '????????'.
In releases of Cygwin before 1.3.20, the group id 401 had a group name
'None'. Since Cygwin release 1.3.20, the group id 401 is shown as
'mkpasswd', indicating the command that should be run to alleviate the
situation.
Also, since Cygwin release 1.3.20, if the current user is present in
/etc/passwd, but that user's login group is not
present in /etc/group, the group name will be shown
as 'mkgroup', again indicating the appropriate command.
To summarize:If the current user doesn't show up in
/etc/passwd, it's group will
be named 'mkpasswd'.Otherwise, if the login group of the current user isn't
in /etc/group, it will be named 'mkgroup'.Otherwise a group not in /etc/group
will be shown as '????????' and a user not in
/etc/passwd will be shown as "????????".
Note that, since the special user and group names are just indicators,
nothing prevents you from actually having a user named `mkpasswd' in
/etc/passwd (or a group named `mkgroup' in
/etc/group). If you do that, however, be aware of
the possible confusion.