POSIX accounts, permission, and securityThis section discusses how the Windows security model is
utilized in Cygwin to implement POSIX account information, POSIX-like
permissions, and how the Windows authentication model is used to allow
cygwin applications to switch users in a POSIX-like fashion.The setting of POSIX-like file and directory permissions is
controlled by the mount option
(no)acl which is set to acl by
default.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.POSIX concepts and in particular the POSIX security model are not
discussed here, but assumed to be understood by the reader. If you
don't know the POSIX security model, search the web for beginner
documentation.Brief overview of Windows securityIn the Windows security model, almost any "object" is securable.
"Objects" are files, processes, threads, semaphores, etc.Every object has a data structure attached, called a "security
descriptor" (SD). The SD contains all information necessary to control
who can access an object, and to determine what they are allowed to do
to or with it. 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. We ignore it here.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
Active Directory (AD) domains. SIDs are basically comparable to POSIX
user ids (UIDs) and group ids (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, as a string of numerical fields separated by hyphen
characters. 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 first field is always "S", which is just a notational convention
to show that this is a SID. The second field is the version number of
the SID structure, So far there exists only one version of SIDs, so this
field is always 1. The third and fourth fields represent the "authority"
which can be thought of as a type or category of SIDs. There are a
couple of builtin accounts and accounts with very special meaning which
have certain well known values in these third and fourth fields.
However, computer and domain SIDs always start with "S-1-5-21". The
next three fields, all 32 bit values, represent the unique 96 bit
identifier of the computer system. This is a hopefully unique value all
over the world, but in practice it's sufficient if the computer 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
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. All machines on the network will
treat these SIDs as identifying two separate accounts. One is
"FOO\johndoe", the other one is "BAR\johndoe" or "johndoe@bar.local".
Different SID, different account. Full stop. Starting with Cygwin 1.7.34, Cygwin uses an automatic, internal
translation from Windows SID to POSIX UID/GID. This mechanism, which is
the preferred method for the SID<=>UID/GID mapping, is described in
detail in .Prior to Cygwin 1.7.34, the last part of the SID, the so called
"Relative IDentifier" (RID), was by default used as UID and/or GID
when you created the /etc/passwd and
/etc/group files using the
mkpasswd and
mkgroup tools.
These tools as well as reading accounts from /etc/passwd
and /etc/group files is still present in recent
versions of Cygwin, but you should switch to the aforementioned
automatic translation, unless you have very specific needs. Again,
see for the details.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 unix-style 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 circumstances under which a process is
running, rather than 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 the MSDN document Well-known
SIDs. The Cygwin package called "csih" provides a tool,
/usr/lib/csih/getAccountName.exe, which can be used to print the
(possibly localized) name for the various 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 member of the administrators
group on "foo" when logging on to "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. But there's a problem with the definition of a "correct" ACL
which disallows mapping of certain POSIX permissions cleanly. See
.POSIX is able to create only three different permissions? Not quite.
Newer operating systems and file systems on POSIX systems also provide
access control lists. Two different APIs exist for accessing these
ACLs, the Solaris API and the POSIX API. Cygwin implements the original
Solaris API to access Windows ACLs in a Unixy way. Online man pages for the
Solaris ACL API can be found on
http://docs.oracle.com.
For an overview see acl(5).Mapping Windows accounts to POSIX accounts
For as long as Cygwin has existed, it has stored user and group information in
/etc/passwd and /etc/group files.
Under the assumption that these files would never be too large, the first
process in a process tree, as well as every execing process within the tree
would parse them into structures in memory. Thus every Cygwin process would
contain an expanded copy of the full information from
/etc/passwd and /etc/group.
This approach has a few downsides. One of them is that the idea that these
files will always be small, is flawed. Another one is that reading the entire
file is most of the time entirely useless, since most processes only
need information on their own user and the primary group. Last but not
least, the passwd and group files have to be maintained separately from
the already existing Windows user databases, the local SAM and Active
Directory.
On the other hand, we have to have this mapping between Windows SIDs and
POSIX uid/gid values, so we need a mechanism to convert SIDs to uid/gid
values and vice versa.
Microsoft "Services for UNIX" (SFU) (deprecated since Windows 8/Server 2012)
never used passwd/group files. Rather, SFU used a fixed, computational mapping
between SIDs and POSIX uid/gid which even has Active Directory support. It
allows us to generate uid/gid values from SIDs and vice versa. The mechanism is
documented, albeit in a confusing way and spread over multiple MSDN articles.
Starting with Cygwin 1.7.34, Cygwin utilizes an approach inspired by the
mapping method as implemented by SFU, with a few differences for backward
compatibility and to handle some border cases differently.
Mapping Windows SIDs to POSIX uid/gid values
The following description assumes you're comfortable with the concept of
Windows SIDs and RIDs. For a brief introduction, see
.
Cygwin's mapping between SIDs and uid/gid values works in two ways.
Read /etc/passwd and
/etc/group files if they exist, just as in the olden
days, mainly for backward compatibility.If no files are present, or if an entry is missing in the files,
ask Windows.
At least, that's the default behaviour now. It will be configurable
using a file /etc/nsswitch.conf, which is discussed in
. Let's explore the default
for now.
If the passwd or group files are present, they will be scanned on demand as
soon as a mapping from SIDs to uid/gid or account names is required. The new
mechanism will never read the entire file into memory, but only scan for
the requested entry and cache this one in memory.
If no entry is found, or no passwd or group file was present, Cygwin
will ask the OS.
If the first process in a Cygwin process tree determines that no
/etc/passwd or /etc/group file is
present, no other process in the entire process tree will try to read the files
later on. This is done for self-preservation. It's rather bad if the uid
or gid of a user changes during the lifetime of a process tree.
For the same reason, if you delete the /etc/passwd
or /etc/group file, this will be ignored. The passwd
and group records read from the files will persist in memory until either a
new /etc/passwd or /etc/group
is created, or you exit all processes in the current process tree.
See the note in for some
comprehensive examples.
So if we've drawn a blank reading the files, we're going to ask the OS.
First thing, we ask the local machine for the SID or the username. The
OS functions
LookupAccountSid
and
LookupAccountName
are pretty intelligent. They have all the stuff built in to ask for any
account of the local machine, the Active Directory domain of the machine,
the Global Catalog of the forest of the domain, as well as any trusted
domain of our forest for the information. One OS call and we're
practically done...
Except, the calls only return the mapping between SID, account name and the
account's domain. We don't have a mapping to POSIX uid/gid and we're missing
information on the user's home dir and login shell.
Let's discuss the SID<=>uid/gid mapping first. Here's how it works.
Well-known
SIDs
in the NT_AUTHORITY domain of the S-1-5-RID type, or aliases of the
S-1-5-32-RID type are mapped to the uid/gid value RID. Examples:
"SYSTEM" S-1-5-18 <=> uid/gid: 18
"Users" S-1-5-32-545 <=> uid/gid: 545
Other well-known SIDs in the NT_AUTHORITY domain (S-1-5-X-RID):
S-1-5-X-RID <=> uid/gid: 0x1000 * X + RID
Example:
"NTLM Authentication" S-1-5-64-10 <=> uid/gid: 0x4000A == 262154
Other well-known SIDs:
S-1-X-Y <=> uid/gid: 0x10000 + 0x100 * X + Y
Example:
"LOCAL" S-1-2-0 <=> uid/gid: 0x10200 == 66048
"Creator Group" S-1-3-1 <=> uid/gid: 0x10301 == 66305
Logon SIDs: The LogonSid of the current user's session is converted to the
fixed uid 0xfff == 4095 and named "CurrentSession". Any other LogonSid is
converted to the fixed uid 0xffe == 4094 and named "OtherSession".
Mandatory Labels:
S-1-16-RID <=> uid/gid: 0x60000 + RID
Example:
"Medium Mandatory Level" S-1-16-8192 <=> uid/gid: 0x62000 == 401408
Accounts from the local machine's user DB (SAM):
S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x30000 + RID
Example:
"Administrator" S-1-5-21-X-Y-Z-500 <=> uid/gid: 0x301f4 == 197108
Accounts from the machine's primary domain:
S-1-5-21-X-Y-Z-RID <=> uid/gid: 0x100000 + RID
Example:
"Domain Users" S-1-5-21-X-Y-Z-513 <=> uid/gid: 0x100201 == 1049089
Accounts from a trusted domain of the machine's primary domain:
S-1-5-21-X-Y-Z-RID <=> uid/gid: trustPosixOffset(domain) + RID
trustPosixOffset? This needs a bit of explanation. This
value exists in Windows domains already since before Active Directory days.
What happens is this. If you create a domain trust between two domains, a
trustedDomain entry will be added to both databases. It describes how
this domain trusts the other domain.
One attribute of a trust is a 32 bit value called
trustPosixOffset For each new trust,
trustPosixOffset will get some automatic value. In recent
AD domain implementations, the first trusted domain will get
trustPosixOffset set to 0x80000000. Following domains will
get lower values. Unfortunately the domain admins are allowed to set the
trustPosixOffset value for each trusted domain to some
arbitrary 32 bit value, no matter what the other
trustPosixOffset are set to, thus allowing any kind of
collisions between the trustPosixOffset values of domains.
That's not exactly helpful, but as the user of this value, we have to
trust the domain admins to set
trustPosixOffset to sensible values, or to keep it at the
system chosen defaults.
So, for the first (or only) trusted domain of your domain, the automatic offset
is 0x80000000. An example for a user of that trusted domain is
S-1-5-21-X-Y-Z-1234 <=> uid/gid 0x800004d2 == 2147484882
There's one problem with this approach. Assuming you're running in the context
of a local SAM user on a domain member machine. Local users don't have the
right to fetch this kind of domain information from the DC, they'll get
permission denied. In this case Cygwin will fake a sensible
trustPosixOffset value.
Another problem is if the AD administrators chose an unreasonably small
trustPosixOffset value. Anything below the hexadecimal
value 0x100000 (the POSIX offset of the primary domain) is bound to produce
collisions with system accounts as well as local accounts. The right thing
to do in this case is to notify your administrator of the problem and to ask
for moving the offset to a more reasonable value. However, to reduce the
probability for collisions, Cygwin overrides this offset with a sensible
fixed replacement offset.
Local accounts from another machine in the network:
There's no SID<=>uid/gid mapping implemented for this case. The problem
is, there's no way to generate a bijective mapping. There's no central place
which keeps an analogue of the trustPosixOffset, and there's
the additional problem that the
LookupAccountSid
and
LookupAccountName
functions cannnot resolve the SIDs, unless they know the name of the machine
this SID comes from. And even then it will probably suffer a
Permission denied error when trying to ask the machine
for its local account.
Now we have a semi-bijective mapping between SIDs and POSIX uid/gid values,
but given that we have potentially users and groups in different domains having
the same name, how do we uniquely distinguish between them by name? Well, we
can do that by making their names unique in a per-machine way. Dependent on
the domain membership of the account, and dependent of the machine being a
domain member or not, the user and group names will be generated using a domain
prefix and a separator character between domain and account name.
The separator character is the plus sign, +.
Well-known and builtin accounts will be named as in Windows:
"SYSTEM", "LOCAL", "Medium Mandatory Level", ...
If the machine is not a domain member machine, only local accounts can be resolved
into names, so for ease of use, just the account names are used as Cygwin
user/group names:
"corinna", "bigfoot", "None", ...
If the machine is a domain member machine, all accounts from the primary domain
of the machine are mapped to Cygwin names without domain prefix:
"corinna", "bigfoot", "Domain Users", ...
while accounts from other domains are prepended by their domain:
"DOMAIN1+corinna", "DOMAIN2+bigfoot", "DOMAIN3+Domain Users", ...
Local machine accounts of a domain member machine get a Cygwin user name the
same way as accounts from another domain: The local machine name gets
prepended:
"MYMACHINE+corinna", "MYMACHINE+bigfoot", "MYMACHINE+None", ...
If LookupAccountSid fails, Cygwin checks the accounts against the known trusted
domains. If the account is from one of the trusted domains, an artificial
account name is created. It consists of the domain name, and a special name
created from the account RID:
"MY_DOM+User(1234)", "MY_DOM+Group(5678)"
Otherwise we know nothing about this SID, so it will be mapped to the
fake accounts Unknown+User/Unknown+Group
with uid/gid -1.
Caching account information
The information fetched from the Windows account database or the
/etc/passwd and /etc/group files is
cached by the process. The cached information is inherited by Cygwin child
processes. A Cygwin process invoked from a Windows command, such as CMD.exe,
will start a new Cygwin process tree and the caching starts from scratch
(unless cygserver is
running, but read on).
While usually working fine, this has some drawbacks. Consider a shell calling
id. id fetches all group information
from the current token and caches them. Unfortunately id
doesn't start any child processes, so the information is lost as soon as
id exits.
But there's another caching mechanism available. If
cygserver is running
it will provide passwd and group entry caching for all processes in every Cygwin
process tree started after
cygserver. So, if
you start a Cygwin Terminal and
cygserver is running
at the time, mintty, the shell, and all child processes will
use cygserver caching.
If you start a Cygwin Terminal and
cygserver is not
running at the time, none of the processes started inside this terminal window
will use cygserver
caching.
The advantage of
cygserver caching is
that it's system-wide and, as long as
cygserver is running,
unforgetful. Every Cygwin process on the system will have the
cygserver cache at
its service. Additionally, all information requested from
cygserver once, will
be cached inside the process itself and, again, propagated to child processes.
If you automatically start Cygwin processes as Windows services at system
startup, you may wish to consider starting
cygserver first in
order to take advantage of this system-wide caching. To assure that
cygserver has started
prior to starting sshd or other Cygwin processes, you may
wish to create service startup dependencies.
Cygserver should
probably wait for Windows TCPIP and AFD services before it starts, and then
other Cygwin process should start after
cygserver. Example
Windows commands to accomplish this (after the services already exist) are
shown below. You will need an administrative prompt to run the
sc config commands.
# Delay Cygserver until TCPIP and AFD have started
# Note the (odd) required space character after "depend="
sc config cygserver depend= tcpip/afd
# Delay sshd until after Cygserver has started
# Again note the (odd) required space character after "depend="
sc config sshd depend= cygserver
# View the Cygserver service details
sc qc cygserver
Note that this sc config command
replaces any existing dependencies. The above changes
will not impact the running instance, only future instances.
# To remove all dependencies from the cygserver service
sc config cygserver depend= /
Cygwin user names, home dirs, login shells
Obviously, if you don't maintain passwd and
group files, you need to have a way to maintain the other
fields of a passwd entry as well. A couple of things come to mind:
You want to use a Cygwin username different from your Windows username.
This is only supported via /etc/passwd. A Cygwin
username maintained in the Windows user databases would require very costly
(read: slow) search operations.
You want to change the primary group of a user. For AD accounts this is
not supported. The primary group of a user is always the Windows
primary group set in Active Directory and can't be changed. For SAM
accounts, you can add the primary group to the SAM
description field of the user. See for more info.
You want a home dir different from the default
/home/$USERNAME.
You want to specify a different login shell than /bin/bash.
You want to add specific content to the pw_gecos field.
For simple needs you can create /etc/passwd and/or
/etc/group files with entries for your account
and tweak that.
For bigger installations, maintaining per-client files is rather troublesome.
Also, no two environments are the same, so the needs are pretty different.
Therefore Cygwin supports configuring how to fetch home directory,
login shell, and gecos information in /etc/nsswitch.conf. See the next
section for detailed information how to configure Cygwin's account handling.
The /etc/nsswitch.conf file
On Linux and some other UNIXy OSes, we have a file called
/etc/nsswitch.conf.
Among other things, it determines how passwd and group entries are generated.
That's what Cygwin now provides as well.
The /etc/nsswitch.conf file is optional. If you don't
have one, Cygwin uses sensible defaults.
The /etc/nsswitch.conf file is read exactly once by
the first process of a Cygwin process tree. If there was no
/etc/nsswitch.conf file when this first process started,
then no other process in the running Cygwin process tree will try to read the
file.
If you create or change /etc/nsswitch.conf, you have to
restart all Cygwin processes that need to see the change. If the process
you want to see the change is a child of another process, you need to restart
all of that process's parents, too.
For example, if you run vim inside the default Cygwin
Terminal, vim is a child of your shell, which is a child
of mintty. If you edit
/etc/nsswitch.conf in that vim
instance, your shell won't immediately see the change, nor will
vim if you restart it from that same shell instance.
This is because both are getting their nsswitch information from their
ancestor, mintty. You have to start a fresh terminal
window for the change to take effect.
By contrast, if you leave that Cygwin Terminal window open after making the
change to /etc/nsswitch.conf, then restart a Cygwin
service like cron, cron will see the
change, because it is not a child of mintty or any other
Cygwin process. (Technically, it is a child of cygrunsrv,
but that instance also restarts when you restart the service.)
The reason we point all this out is that the requirements for restarting
things are not quite as stringent as when you replace
cygwin1.dll. If you have three process trees, you have
three independent copies of the nsswitch information. If you start a fresh
process tree, it will see the changes. As long as any process in an existing
process tree remains running, all processes in that tree will continue to use
the old information.
So, what settings can we perform with /etc/nsswitch.conf?
Let's start with an example /etc/nsswitch.conf file
set up to all default values:
# /etc/nsswitch.conf
passwd: files db
group: files db
db_enum: cache builtin
db_home: /home/%U
db_shell: /bin/bash
db_gecos: <empty>
The /etc/nsswitch.conf syntax
The first line, starting with a hash # is a comment.
The hash character starts a comment, just as in shell scripts. Everything
up to the end of the line is ignored. So this:
foo: bar # baz
means, set "foo" to value "bar", ignore everything after the hash.
The other lines define the available settings. The first word up to a
colon is a keyword. Note that the colon must follow
immediately after the keyword. This is a valid line:
foo: bar
This is not valid:
foo : bar
Apart from this restriction, the remainder of the line can have as
many spaces and TABs as you like.
The passwd: and group: settings
The two lines starting with the keywords passwd: and
group: define where Cygwin gets its passwd and group
information from. files means, fetch the information
from the corresponding file in the /etc directory. db
means, fetch the information from the Windows account databases, the SAM
for local accounts, Active Directory for domain account. Examples:
passwd: files
Read passwd entries only from /etc/passwd.
group: db
Read group entries only from SAM/AD.
group: files # db
Read group entries only from /etc/group
(db is only a comment).
passwd: files db
Read passwd entries from /etc/passwd. If a user account
isn't found, try to find it in SAM or AD. This is the default for both,
passwd and group information.
group: db files
This is a valid entry, but the order will be ignored by Cygwin. If both
settings, files and db are specified,
Cygwin will always try the files first, then the db.
passwd: and group: are the two basic
settings defining where to get the account information from. The following
settings starting with db_ define certain aspects of the
Windows account database search and how to generate passwd
and group information from the database.
The db_enum: settingdb_enum: defines the depth of a database search, if an
application calls one of the enumeration functions
getpwent
or getgrent.
The problem with these functions is, they neither allow to define how many
entries will be enumerated when calling them in a loop, nor do they
allow to add some filter criteria. They were designed back in the days,
when only /etc/passwd and /etc/group
files existed and the number of user accounts on a typical UNIX system was
seldomly a three-digit number.
These days, with user and group databases sometimes going in the
six-digit range, they are a potential burden. For that reason, Cygwin
does not enumerate all user or group accounts by default, but rather
just a very small list, consisting only of the accounts cached in memory
by the current process, as well as a handful of predefined builtin
accounts.
db_enum: allows to specify the accounts to enumerate in a
fine-grained manner. It takes a list of sources as argument:
db_enum: source1 source2 ...
The recognized sources are the following:
noneNo output from
getpwent/getgrent
at all.allThe opposite. Enumerates accounts from all known sources,
including all trusted domains.cacheEnumerate all accounts currently cached in memory.builtinEnumerate the predefined builtin accounts for backward
compatibility. These are five passwd accounts (SYSTEM,
LocalService, NetworkService, Administrators, TrustedInstaller)
and two group accounts (SYSTEM and TrustedInstaller).filesEnumerate the accounts from /etc/passwd or
/etc/group.localEnumerate all accounts from the local SAM.primaryEnumerate all accounts from the primary domain.alltrustedEnumerate all accounts from all trusted domains.some.domainEnumerate all accounts from the trusted domain some.domain. The
trusted domain can be given as Netbios flat name (MY_DOMAIN) or
as dns domain name (my_domain.corp). In contrast to the
aforementioned fixed source keywords, distinct domain names are
caseinsensitive. Only domains which are actually trusted domains
are enumerated. Unknown domains are simply ignored.
Please note that getpwent/getgrent
do not test if an account was already listed from another
source, so an account can easily show up twice or three times. Such a test
would be rather tricky, nor does the Linux implementation perform such test.
Here are a few examples for /etc/nsswitch.conf:
db_enum: none
No output from getpwent/getgrent
at all. The first call to the function immediately returns a NULL pointer.
db_enum: cache files
Enumerate all accounts cached by the current process, plus all entries
from either the /etc/passwd or /etc/group file.
db_enum: cache local primary
Enumerate all accounts cached by the current process, all accounts from the SAM
of the local machine, and all accounts from the primary domain of the machine.
db_enum: local primary alltrusted
Enumerate the accounts from the machine's SAM, from the primary domain of the
machine, and from all trusted domains.
db_enum: primary domain1.corp sub.domain.corp domain2.net
Enumerate the accounts from the primary domain and from the domains
domain1.corp, sub.domain.corp and domain2.net.
db_enum: all
Enumerate everything and the kitchen sink.
Settings defining how to create the passwd entry/etc/nsswitch.conf supports three settings to configure
where to get the pw_dir, pw_shell, and pw_gecos content of a
passwd entry from:
db_home: schema... # Define how to fetch the pw_dir entry.
db_shell: schema... # Define how to fetch the pw_shell entry.
db_gecos: schema... # Define how to fetch the pw_gecos entry.
"schema..." is a list of up to four space-separated schemata:
db_FOO: schema1 schema2 ...
When generating a passwd entry, Cygwin tries the schemata in order. If
the first schema returns an empty string, it skips to the second, and so
on. Schemata only supported on AD are silently skipped for SAM accounts
and on non-AD machines.
Four schemata are predefined, two schemata are variable. The predefined
schemata are the following:
windowsUtilizes typical Windows settings. Supported for AD and SAM
accounts.cygwinUtilizes the cygwinUser AD schema extension. This schema
extension is available via a schema extension file
/usr/share/cygwin/cygwin.ldif.
See for
more information.unixUtilizes the posixAccount schema attributes per
RFC 2307.
The posixAccount schema is available by default in Windows
Server, but typically only utilized when installing the
Active Directory "Server for NIS" feature (which is deprecated
since Server 2012 R2).
See also .
descUtilizes XML-style attributes in the description attribute.
Supported for AD and SAM accounts.
See
for a more detailed description.
The variable schemata are as follows. Note that the leading characters
(@ and /) are an integral part of the
definition.
@ad_attributead_attribute is any arbitrary AD attribute
name which should (ideally) be available in the User class or
in any attached auxiliary class. It's always treated as a
single string argument. Only the first string of a multi-string
attributes will be read./pathAn arbitrary string, typically a path. The leading slash is
required. Given that a single, fixed path for all users
only makes marginal sense, the /path schema supports wildcards.
A wildcard is a per-cent (%) character,
followed by another character giving the meaning. The supported
wildcard characters are:
%uThe Cygwin username (that's lowercase
u).%UThe Windows username (that's uppercase
U).%DWindows domain in NetBIOS style.%HWindows home directory in POSIX style. Note that,
for the db_home: setting, this
only makes sense right after the preceeding slash,
as in
db_home: /%H/cygwin
%_Since space and TAB characters are used to separate
the schemata, a space in the filename has to be
given as %_ (that's an
underscore).%%A per-cent character.Any other %X expression is treated as if
the character X has been given alone.
The exact meaning of a schema depends on the setting it's used for. The
following sections explain the settings in detail.
The db_home settingThe db_home: setting
The db_home: setting defines how Cygwin fetches the user's
home directory, or, more precise, the content of the pw_dir
member of the user's passwd entry. The following list describes the meaning
of each schema when used with db_home:windowsThe user's home directory is set to the same directory which is
used as Windows home directory. This is the
homeDirectory AD attribute.
For SAM accounts, this is equivalent to the "Home folder" setting
in SAM. If both attributes are unset, Cygwin falls back to the
user's local profile directory, typically something along the
lines of C:\Users\$USERNAME. Of course, the
Windows directory is converted to POSIX-style by Cygwin.
cygwinAD only: The user's home directory is set to the POSIX path given
in the cygwinHome attribute from the
cygwinUser auxiliary class.
See also .
unixAD only: The user's home directory is set to the POSIX path given
in the unixHomeDirectory attribute from the
posixAccount auxiliary class.
See also .
descThe user's home directory is set to the POSIX path given in the
home="..." XML-alike setting in the user's
description attribute in SAM or AD.
See
for a detailed description.@ad_attributeAD only: The user's home directory is set to the path given
in the ad_attribute attribute. The path
can be given as Windows or POSIX path./pathThe user's home directory is set to the given POSIX path.
Remember the wildcards described in
.FallbackIf none of the schemes given for db_home:
define a non-empty directory, the user's home directory is set to
/home/$USERNAME.
As has been briefly mentioned before, the default setting for
db_home: is
db_home: /home/%U
So by default, Cygwin just sets the home dir to
/home/$USERNAME.
The db_shell settingThe db_shell: setting
The db_shell: setting defines how Cygwin fetches the user's
login shell, the content of the pw_shell member of the
user's passwd entry. The following list describes the meaning of each schema
when used with db_shell:windowsThe windows schema is ignored for now.
The logical choice would be CMD, but that introduces some
problems, for instance the fact that CMD has no concept of
running as login shell. This may change
in future.cygwinAD only: The user's home directory is set to the POSIX path given
in the cygwinShell attribute from the
cygwinUser auxiliary class.
See also .
unixAD only: The user's login shell is set to the POSIX path given
in the loginShell attribute from the
posixAccount auxiliary class.
See also .
descThe user's login shell is set to the POSIX path given in the
shell="..." XML-alike setting in the user's
description attribute in SAM or AD.
See
for a detailed description.@ad_attributeAD only: The user's login shell is set to the path given
in the ad_attribute attribute. The path
can be given as Windows or POSIX path./pathThe user's login shell is set to the given POSIX path.
Albeit not being as important here, the wildcards described in
are also available for specifying a login shell path.FallbackIf none of the schemes given for db_shell:
define a non-empty pathname, the user's login shell is set to
/bin/bash.
As for db_home:, the default setting for
db_shell: is pretty much a constant
db_shell: /bin/bash
The db_gecos settingThe db_gecos: setting
The db_gecos: setting defines how to fetch additional
content for the pw_gecos member of the user's passwd entry.
There's always a fixed, Cygwin-specific part in the pw_gecos
field for identifying the account. However, an administrator might want to
add informative content like, for instance, the user's full name. That's
what the db_gecos: setting is for.
The following list describes the meaning of each schema when used with
db_gecos:windowsAdd the AD displayName attribute or, for
SAM accounts, the "Full name" entry to the
pw_gecos field.cygwinAD only: The content of the cygwinGecos
attribute from the cygwinUser auxiliary class
is added to pw_gecos.
See also .
unixAD only: The content of the gecos attribute
from the posixAccount auxiliary class
is added to pw_gecos.
See also .
descThe content of the gecos="..." XML-alike setting in the user's
description attribute in SAM or AD is added
to pw_gecos.
See
for a detailed description.@ad_attributeAD only: The content of the ad_attribute
attribute is added to pw_gecos./pathThe string following the slash is added to
pw_gecos. Here, the wildcards described in
may come in handy.FallbackIf none of the schemes given for db_gecos:
define a non-empty pathname, nothing is added to
pw_gecos.
The default setting for db_gecos: is the empty string.
The cygwin schema
The cygwin schema is based on a Cygwin-specific Active
Directory schema extension. Using this schema extension allows to maintain
Cygwin-specific settings entirely within AD, without colliding with any other
schema.
The cygwin schema extension is available in a default Cygwin installation
in the file /usr/share/cygwin/cygwin.ldif. To install
the schema extension, you have to be schema admin, and you have to run the
ldifde command on the schema master. The installation
itself is rather simple. Assuming you're schema admin and running a shell
with administrative privileges:
$ cd /usr/share/cygwin
$ ldifde -i -f cygwin.ldif -k -c "CN=schema,CN=Configuration,DC=X" #schemaNamingContext
Afterwards, the auxiliary class cygwinUser is attached to
the class User, and the auxiliary class
cygwinGroup is attached to the class
Group. The new attributes can be immediately edited
using ADSI Edit.
At the time of writing the following attributes are utilized by Cygwin:
cygwinHomeUsed as Cygwin home directory with db_home: cygwin.
See .cygwinShellUsed as Cygwin login shell with db_shell: cygwin.
See .cygwinGecosContent will be added to the pw_gecos field with
db_gecos: cygwin.
See .The unix schema
The unix schema utilizes the
posixAccount attribute extension. This is one of two
schema extensions which are connected to AD accounts, available by default.
They are usually not set, unless used by
the Active Directory Server for NIS feature (deprecated
since Server 2012 R2).
Two schemata are interesting for Cygwin, posixAccount,
connected to user accounts, and posixGroup, connected
to group accounts. Both follow the description of RFC 2307,
an Approach for Using LDAP as
a Network Information Service.
The user attributes utilized by Cygwin are:
unixHomeDirectoryUsed as Cygwin home directory with db_home: unix.
See .loginShellUsed as Cygwin login shell with db_shell: unix.
See .gecosContent will be added to the pw_gecos field with
db_gecos: unix.
See .uidNumberSee and
.
The group attributes utilized by Cygwin are:
gidNumberSee and
.
Apart from power shell scripting or inventing new CLI tools, these attributes
can be changed using the Attribute Editor tab in the user
properties dialog of the Active Directory Users and Computers
MMC snap-in. Alternatively, if the Server for NIS
administration feature has been installed, there will be a
UNIX Attributes tab which contains the required fields,
except for the gecos field. Last resort is ADSI Edit.
The desc schema
When using user accounts from the local account database, the SAM, there
are only a very limited number of settings available. In contrast to
Active Directory there's no way to add fields to a user's entry. You have
to make do with the fields available. The method to utilize the
description field has been mainly introduced for those
accounts, usually the only ones a home user has. However, for symmetry,
and because there may be a reason to use this in an AD environment, this
schema is also supported for AD users.
The presentation of local user account settings on Windows is confusing,
to say the least. The description field is not visible at
all in the user settings available via the User Accounts
control settings. And while it's called Description in the
Local Users and Groups MMC snap-in (available, for instance,
via the Computer Management GUI), in the command
line tool net user the same field is called
comment. The latter is especially confusing for
AD admins, because the comment attribute in AD is called
usercomment on the command line. Confused? Never mind,
you're not the only one...
Fortunately you can utilize the description field even if
you're running a "home edition" of Windows, by using the command line. The
net user command allows to set all values in the SAM, even
if the GUI is crippled.
A Cygwin SAM comment entry looks like this:
<cygwin key="value" key="value" [...] />
The supported keys are:
home="value"Sets the Cygwin home dir to value.shell="value"Sets the Cygwin login shell to value.gecos="value"Adds the string value to the user's gecos field.
The next two settings are only supported for SAM accounts.
group="value"Sets the Cygwin primary group of the account to value, provided that
the user is already a member of that group.
This allows to override the default None primary
group for local accounts. One nice idea here is, for instance,
group="Users".unix="value"Sets the NFS/Samba uid of the user to the decimal value.
See and
.
The <cygwin .../> string can start at any point in the comment, but
you have to follow the rules:
It starts with "<cygwin " and ends with "/>".
The "cygwin" string and the key names have to be lowercase.
No spaces between key and "value", just the equal sign.
The value must be placed within double quotes and it must not contain a double
quote itself. The double quotes are required for the decimal values as well!
There's also a length restriction imposed by Windows. The
description entry has a maximum length of 1023 characters.
CMD example:
net user corinna /comment:"<cygwin home=\"/home/foo\"/>"
Bash example (use single quotes):
net user corinna /comment:'<cygwin home="/home/foo"/>'
For changing group comments, use the `net localgroup' command. The supported
key/value pair for SAM groups are:
unix="value"Sets the NFS/Samba gid of the group to the decimal value.
See and
.NFS account mapping
Microsoft's NFS client does not map the uid/gid values on the NFS shares
to SIDs. There's no such thing as a (fake) security descriptor returned
to the application. Rather, via an undocumented API an application can
fetch RFC 1813
compatible NFSv3 stat information from the share. This is what Cygwin is
using to show stat information for files on NFS shares.
The problem is, while all other information in this stat record, like
timestamps, file size etc., can be used by Cygwin, Cygwin had no way to
map the values of the st_uid and st_gid members to a Windows SID for a
long time. So it just faked the file owner info and claimed that it's
you.
However, SFU has, over time, developed multiple methods to map UNIX
uid/gid values on NFS shares to Windows SIDs. You'll find the full
documentation of the mapping methods in
NFS Identity Mapping in Windows Server 2012
Cygwin now utilizes the
RFC 2307
mapping for this purpose. This is most of the time provided by an AD domain,
but it could also be a standalone LDAP mapping server. Per
RFC 2307, the uid is
in the attribute uidNumber. For groups, the gid is in the
gidNumber attribute.
See .
When Cygwin stat()s files on an NFS share, it asks the mapping server via
LDAP in two different ways, depending on the role of the mapping server.
If the server is an AD domain controller, it asks for an account with
uidNumber attribute == st_uid field of
the stat record returned by NFS. If an account matches, AD returns the
Windows SID, so we have an immediate mapping from UNIX uid to a Windows SID,
if the user account has a valid uidNumber attribute. For
groups, the method is the same, just that Cygwin asks for a group with
gidNumber attribute == st_gid field of the
stat record.
If the server is a standalone LDAP mapping server Cygwin asks for the
same uidNumber/gidNumber attributes, but
it can't expect that the LDAP server knows anything about Windows SIDs.
Rather, the mapping server returns the account name. Cygwin then asks the
DC for an account with this name, and if that succeeds, we have a mapping
between UNIX uid/gid and Windows SIDs.
The mapping will be cached for the lifetime of the process, and inherited
by child processes.
Samba account mapping
A fully set up Samba file server with domain integration is running winbindd to
map Windows SIDs to artificially created UNIX uids and gids, and this mapping is
transparent within the domain, so Cygwin doesn't have to do anything special.
However, setting up winbindd isn't for everybody, and it fails to map
Windows accounts to already existing UNIX users or groups. In contrast
to NFS, Samba returns security descriptors, but unmapped UNIX accounts
get special SIDs:
A UNIX user account with uid X is mapped to the Windows SID S-1-22-1-X.
A UNIX group account with gid X is mapped to SID S-1-22-2-X.
As you can see, even though we have SIDs, they just reflect the actual
uid/gid values on the UNIX box in the RID value. It's only marginally
different from the NFS method, so why not just use the same method as
for NFS?
That's what Cygwin will do. If it encounters a S-1-22-x-y SID, it
will perform the same
RFC 2307
mapping as for NFS shares.
For home users without any Windows domain or LDAP server per
RFC 2307,
but with a Linux machine running Samba, just add this information to
your SAM account. Assuming the uid of your Linux user account is 505
and the gid of your primary group is, say, 100, just add the values to
your SAM user and group accounts. The following example assumes you
didn't already add something else to the comment field.
To your user's SAM comment (remember: called Description
in the GUI),
add:
<cygwin group="Users" unix="505"/>
To the Users group SAM comment add:
<cygwin unix="100"/>
This should be sufficient to work on your Samba share and to see
all files owned by your Linux user account as your files.
File permissionsOn NTFS and if the noacl mount option is not
specified for a mount point, Cygwin sets file permissions as on POSIX
systems. Basically this is done by defining a Security Descriptor 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".There's just one problem when trying to map the POSIX permission model
onto the Windows permission model.There's a leak in the definition of a "correct" ACL which disallows a
certain POSIX permission setting. The official documentation explains in short
the following:The requested permissions are checked against all
ACEs of the user as well as all groups the user is member of. The
permissions given in these user and groups access allowed ACEs are
accumulated and the resulting set is the set of permissions of that
user given for that object.The order of ACEs is important. The system reads them in
sequence until either any single requested permission is denied or all
requested permissions are granted. Reading stops when this condition is
met. Later ACEs are not taken into account.All access denied ACEs should precede any access allowed ACE. ACLs
following this rule are called "canonical".Note that the last rule is a preference or a definition of
correctness. It's not an absolute requirement. All Windows kernels
will correctly deal with the ACL regardless of the order of allow and
deny ACEs. The second rule is not modified to get the ACEs in the
preferred order.Unfortunately the security tab in the file properties dialog of
the Windows Explorer insists to rearrange the order of the ACEs to
canonical order before you can read them. Thank God, the sort order
remains unchanged if one presses the Cancel button. But don't even
think of pressing OK...Canonical ACLs are unable to reflect each possible combination
of POSIX permissions. Example:
rw-r-xrw-
Ok, so here's the first try to create a matching ACL, assuming
the Windows permissions only have three bits, as their POSIX counterpart:
UserAllow: 110
GroupAllow: 101
OthersAllow: 110
Hmm, because of the accumulation of allow rights the user may
execute because the group may execute.Second 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.Third 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 canonical order 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 on all supported versions of Windows. Only the GUIs
aren't able (or willing) to deal with that order.Switching the user contextWindows users have been accustomed to the "Switch User" feature, which
switches the entire desktop to another user while leaving the original user's
desktop "suspended". Another Windows feature is the "Run as..." context menu
entry, which allows you to start an application using another user account
when right-clicking on applications and shortcuts.On POSIX systems, this operation can be performed by processes
running under the privileged user accounts (usually the "root" user
account) on a per-process basis. This is called "switching the user
context" for that process, and is performed using the POSIX
setuid and seteuid system
calls.While this sort of feature is available on Windows as well,
Windows does not support the concept of these calls in a simple fashion.
Switching the user context in Windows is generally a tricky process with
lots of "behind the scenes" magic involved.Windows uses so-called `access tokens' to identify a user and its
permissions. Usually the access token is created at logon time and then
it's attached to the starting process. Every new process within a session
inherits the access token from its parent process. Every thread can
get its own access token, which allows, for instance, to define threads
with restricted permissions.Switching the user context with password authenticationTo switch the user context, the process has to request such an access
token for the new user. This is typically done by calling the Win32 API
function LogonUser with the user name and the user's
cleartext password as arguments. If the user exists and the password was
specified correctly, the access token is returned and either used in
ImpersonateLoggedOnUser to change the user context of
the current thread, or in CreateProcessAsUser to
change the user context of a spawned child process.Later versions of Windows define new functions in this context and
there are also functions to manipulate existing access tokens (usually
only to restrict them). Windows Vista also adds subtokens which are
attached to other access tokens which plays an important role in the UAC
(User Access Control) facility of Vista and later. However, none of
these extensions to the original concept are important for this
documentation.Back to this logon with password, how can this be used to
implement set(e)uid? Well, it requires modification
of the calling application. Two Cygwin functions have been introduced
to support porting setuid applications which only
require login with passwords. You only give Cygwin the right access
token and then you can call seteuid or
setuid as usual in POSIX applications. Porting such
a setuid application is illustrated by a short
example:
#include
#endif
[...]
struct passwd *user_pwd_entry = getpwnam (username);
char *cleartext_password = getpass ("Password:");
[...]
#ifdef __CYGWIN__
/* Patch the typical password test. */
{
HANDLE token;
/* Try to get the access token from Windows. */
token = cygwin_logon_user (user_pwd_entry, cleartext_password);
if (token == INVALID_HANDLE_VALUE)
error_exit;
/* Inform Cygwin about the new impersonation token. */
cygwin_set_impersonation_token (token);
/* Cygwin is now able, to switch to that user context by setuid or seteuid calls. */
}
#else
/* Use standard method on non-Cygwin systems. */
hashed_password = crypt (cleartext_password, salt);
if (!user_pwd_entry ||
strcmp (hashed_password, user_pwd_entry->pw_passwd))
error_exit;
#endif /* CYGWIN */
[...]
/* Everything else remains the same! */
setegid (user_pwd_entry->pw_gid);
seteuid (user_pwd_entry->pw_uid);
execl ("/bin/sh", ...);
]]>
Switching the user context without password, Method 1: Kerberos/MsV1_0 S4U authenticationAn unfortunate aspect of the implementation of
set(e)uid is the fact that the calling process
requires the password of the user to switch to. Applications such as
sshd wishing to switch the user context after a
successful public key authentication, or the cron
application which, again, wants to switch the user without any authentication
are stuck here. But there are other ways to get new user tokens.Starting with Cygwin 3.0, Cygwin tries to create a token by using
Windows S4U authentication by default. For a quick
description, see
this blog posting. Cygwin versions prior
to 3.0 tried to creat a user token from scratch using an officially
undocumented function NtCreateToken which
is now disabled.So we just start the servers which have to switch the user context
(sshd, inetd, cron,
...) as Windows services under the SYSTEM (or LocalSystem in the GUI)
account and everything just works. Unfortunately that's too simple.
Using S4U has a drawback.Annoyingly, you don't have the usual comfortable access
to network shares. The reason is that the token has been created
without knowing the password. The password are your credentials
necessary for network access. Thus, if you logon with a password, the
password is stored hidden as "token credentials" within the access token
and used as default logon to access network resources. Since these
credentials are missing from the token created with S4U
or NtCreateToken, you only can access network shares
from the new user's process tree by using explicit authentication, on
the command line for instance:
bash$ net use '\\server\share' /user:DOMAIN\my_user my_users_password
Note that, on some systems, you can't even define a drive letter
to access the share, and under some circumstances the drive letter you
choose collides with a drive letter already used in another session.
Therefore it's better to get used to accessing these shares using the UNC
path as in
bash$ grep foo //server/share/foofile
Switching the user context without password, Method 2: With passwordNot being able to access network shares without having to specify
a cleartext password on the command line or in a script is a harsh problem
for automated logons for testing purposes and similar stuff.Fortunately there is a solution, but it has its own drawbacks.
But, first things first, how does it work? The title of this section
says it all. Instead of trying to logon without password, we just logon
with password. The password gets stored two-way encrypted in a hidden,
obfuscated area of the registry, the LSA private registry area. This
part of the registry contains, for instance, the passwords of the Windows
services which run under some non-default user account.So what we do is to utilize this registry area for the purpose of
set(e)uid. The Cygwin command passwd -R allows a user to specify
his/her password for storage in this registry area. When this user
tries to login using ssh with public key authentication, Cygwin's
set(e)uid examines the LSA private registry area and
searches for a Cygwin specific key which contains the password. If it
finds it, it calls LogonUser under the hood, using
this password. If that works, LogonUser returns an
access token with all credentials necessary for network access.For good measure, and since this way to implement
set(e)uid is not only used by Cygwin but also by
Microsoft's SFU (Services for Unix), we also look for a key stored by
SFU (using the SFU command regpwd) and use that if it's
available.We got it. A full access token with its own logon session, with
all network credentials. Hmm, that's heaven...Back on earth, what about the drawbacks?First, adding a password to the LSA private registry area
requires administrative access. So calling passwd -R
as a normal user will fail! Cygwin provides a workaround for
this. If cygserver is started as a service running
under the SYSTEM account (which is the default way to run
cygserver) you can use passwd -R
as normal, non-privileged user as well.Second, as aforementioned, the password is two-way encrypted in a
hidden, obfuscated registry area. Only SYSTEM has access to this area
for listing purposes, so, even as an administrator, you can't examine
this area with regedit. Right? No. Every administrator can start
regedit as SYSTEM user, the Internet is your friend here.Additionally, if an administrator knows under which name
the private key is stored (which is well-known since the algorithms
used to create the Cygwin and SFU keys are no secret), every administrator
can access the password of all keys stored this way in the registry.Conclusion: If your system is used exclusively by you, and if
you're also the only administrator of your system, and if your system is
adequately locked down to prevent malicious access, you can safely use
this method. If your machine is part of a network which has
dedicated administrators, and you're not one of these administrators,
but you (think you) can trust your administrators, you can probably
safely use this method.In all other cases, don't use this method. You have been warned.Switching the user context, how does it all fit together?Now we learned about three different ways to switch the user
context using the set(e)uid system call, but
how does set(e)uid really work? Which method does it
use now?The answer is, all three of them. So here's a brief overview
what set(e)uid does under the hood:When set(e)uid is called, it tests if the
user context had been switched by an earlier call already, and if the
new user account is the privileged user account under which the process
had been started originally. If so, it just switches to the original
access token of the process it had been started with.
Next, it tests if an access token has been stored by an earlier call
to cygwin_set_impersonation_token. If so, it tests
if that token matches the requested user account. If so, the stored
token is used for the user context switch.
If not, there's no predefined token which can just be used for
the user context switch, so we have to create a new token. The order
is as follows.Check if the user has stored the logon password in the LSA
private registry area, either under a Cygwin key, or under a SFU key.
If so, use this to call LogonUser. If this
succeeds, we use the resulting token for the user context switch.Otherwise, use the default S4U authentication
to create a token.Older systems, like WOW64 under Windows 7 64 bit, don't support
S4U authentication for local machine accounts. On
these systems Cygwin falls back to an old and otherwise deprecated
method to create a user token from scratch. The underlying system call
is undocumented and has an unfortunate requirement: We have to create a
special account with dangerous permissions to perform this action.
Therefore this is only enabled on affected systems.If all of the above fails, our process has insufficient privileges
to switch the user context at all, so set(e)uid
fails and returns -1, setting errno to EPERM.