OSDN Git Service

* new-features.sgml (ov-new1.7.2): Accommodate name change of getlocale
[pf3gnuchains/pf3gnuchains4x.git] / winsup / doc / ntsec.sgml
1 <sect1 id="ntsec"><title>Using Windows security in Cygwin</title>
2
3 <para>This section discusses how the Windows security model is
4 utilized in Cygwin to implement POSIX-like permissions, as well as how
5 the Windows authentication model is used to allow cygwin applications
6 to switch users in a POSIX-like fashion.</para>
7
8 <para>The setting of POSIX-like file and directory permissions is
9 controlled by the <link linkend="mount-table">mount</link> option
10 <literal>(no)acl</literal> which is set to <literal>acl</literal> by
11 default.</para>
12
13 <para>We start with a short overview.  Note that this overview must
14 be necessarily short.  If you want to learn more about the Windows security
15 model, see the <ulink url="http://msdn.microsoft.com/en-us/library/aa374860(VS.85).aspx">Access Control</ulink> article in MSDN documentation.</para>
16
17 <para>POSIX concepts and specificially the POSIX security model are not
18 discussed here, but assumed to be understood by the reader.  If you
19 don't know the POSIX security model, search the web for beginner
20 documentation.</para>
21
22 <sect2 id="ntsec-common"><title>Overview</title>
23
24 <para>In the Windows security model, almost any "object" is securable.
25 "Objects" are files, processes, threads, semaphores, etc.</para>
26
27 <para>Every object has a data structure attached, called a "security
28 descriptor" (SD).  The SD contains all information necessary to control
29 who can access an object, and to determine what they are allowed to do
30 to or with it.  The SD of an object consists of five parts:</para>
31
32 <itemizedlist spacing="compact">
33 <listitem><para>Flags which control several aspects of this SD. This is
34 not discussed here.</para></listitem>
35 <listitem><para>The SID of the object owner.</para></listitem>
36 <listitem><para>The SID of the object owner group.</para></listitem>
37 <listitem><para>A list of "Access Control Entries" (ACE), called the
38 "Discretionary Access Control List" (DACL).</para></listitem>
39 <listitem><para>Another list of ACEs, called the "Security Access Control List"
40 (SACL), which doesn't matter for our purpose.  We ignore it here.</para></listitem>
41 </itemizedlist>
42
43 <para>Every ACE contains a so-called "Security IDentifier" (SID) and
44 other stuff which is explained a bit later.  Let's talk about the SID first.
45 </para>
46
47 <para>A SID is a unique identifier for users, groups, computers and
48 Active Directory (AD) domains.  SIDs are basically comparable to POSIX
49 user ids (UIDs) and group ids (GIDs), but are more complicated because
50 they are unique across multiple machines or domains.  A SID is a
51 structure of multiple numerical values.  There's a convenient convention
52 to type SIDs, as a string of numerical fields separated by hyphen
53 characters.  Here's an example:</para>
54
55 <para>SID of a machine "foo":</para>
56
57 <screen>
58   S-1-5-21-165875785-1005667432-441284377
59 </screen>
60
61 <para>SID of a user "johndoe" of the system "foo":</para>
62
63 <screen>
64   S-1-5-21-165875785-1005667432-441284377-1023
65 </screen>
66
67 <para>The first field is always "S", which is just a notational convention
68 to show that this is a SID.  The second field is the version number of
69 the SID structure, So far there exists only one version of SIDs, so this
70 field is always 1.  The third and fourth fields represent the "authority"
71 which can be thought of as a type or category of SIDs.  There are a
72 couple of builtin accounts and accounts with very special meaning which
73 have certain well known values in these third and fourth fields.
74 However, computer and domain SIDs always start with "S-1-5-21".  The
75 next three fields, all 32 bit values, represent the unique 96 bit
76 identifier of the computer system.  This is a hopefully unique value all
77 over the world, but in practice it's sufficient if the computer SIDs are
78 unique within a single Windows network.</para>
79
80 <para>As you can see in the above example, SIDs of users (and groups)
81 are identical to the computer SID, except for an additional part, the
82 so-called "relative identifier" (RID).  So the SID of a user is always 
83 uniquely attached to the system on which the account has been generated.</para>
84
85 <para>It's a bit different in domains.  The domain has its own SID, and
86 that SID is identical to the SID of the first domain controller, on
87 which the domain is created.  Domain user SIDs look exactly like the
88 computer user SIDs, the leading part is just the domain SID and the RID
89 is created when the user is created.</para>
90
91 <para>Ok, consider you created a new domain "bar" on some new domain
92 controller and you would like to create a domain account "johndoe":</para>
93
94 <para>SID of a domain "bar.local":</para>
95
96 <screen>
97   S-1-5-21-186985262-1144665072-740312968
98 </screen>
99
100 <para>SID of a user "johndoe" in the domain "bar.local":</para>
101
102 <screen>
103   S-1-5-21-186985262-1144665072-740312968-1207
104 </screen>
105
106 <para>So you now have two accounts called johndoe, one account
107 created on the machine "foo", one created in the domain "bar.local".
108 Both have different SIDs and not even the RID is the same.  How do
109 the systems know it's the same account?  After all, the name is
110 the same, right?  The answer is, these accounts are <emphasis
111 role='bold'>not</emphasis> identical.  All machines on the network will
112 treat these SIDs as identifying two separate accounts.  One is
113 "FOO\johndoe", the other one is "BAR\johndoe" or "johndoe@bar.local".
114 Different SID, different account.  Full stop.  </para>
115
116 <para>The last part of the SID, the so called "Relative IDentifier" (RID),
117 is by default used as UID and/or GID under Cygwin when you create the
118 <filename>/etc/passwd</filename> and <filename>/etc/group</filename>
119 files using the <command><link linkend="mkpasswd">mkpasswd</link></command> and <command><link linkend="mkgroup">mkgroup</link></command>
120 tools.  Domain account UIDs and GIDs are offset by 10000 by default
121 which might be a bit low for very big organizations.  Fortunately there's
122 an option in both tools to change the offset...</para>
123
124 <para>Do you still remember the SIDs with special meaning?  In offical
125 notation they are called "well-known SIDs".  For example, POSIX has no GID
126 for the group of "all users" or "world" or "others".  The last three rwx
127 bits in a unix-style permission value just represent the permissions for
128 "everyone who is not the owner or is member of the owning group".
129 Windows has a SID for these poor souls, the "Everyone" SID.  Other
130 well-known SIDs represent circumstances under which a process is
131 running, rather than actual users or groups.  Here are a few examples
132 for well-known SIDs:</para>
133
134 <screen>
135 Everyone                        S-1-1-0    Simply everyone...
136 Batch                           S-1-5-3    Processes started via the task
137                                            scheduler are member of this group.
138 Interactive                     S-1-5-4    Only processes of users which are
139                                            logged in via an interactive
140                                            session are members here.
141 Authenticated Users             S-1-5-11   Users which have gone through
142                                            the authentication process and
143                                            survived.  Anonymously accessing
144                                            users are not incuded here.
145 SYSTEM                          S-1-5-18   A special account which has all
146                                            kinds of dangerous rights, sort of
147                                            an uber-root account.
148 </screen>
149
150 <para>For a full list please refer to the MSDN document <ulink
151 url="http://msdn.microsoft.com/en-us/library/aa379649.aspx">Well-known
152 SIDs</ulink>.  The Cygwin package called "csih" provides a tool,
153 /usr/lib/csih/getAccountName.exe, which can be used to print the
154 (possibly localized) name for the various well-known SIDS.</para>
155
156 <para>Naturally, well-known SIDs are the same on each machine, so they are
157 not unique to a machine or domain.  They have the same meaning across
158 the Windows network.</para>
159
160 <para>Additionally, there are a couple of well-known builtin groups,
161 which have the same SID on every machine and which have certain user
162 rights by default:</para>
163
164 <screen>
165 administrators                  S-1-5-32-544
166 users                           S-1-5-32-545
167 guests                          S-1-5-32-546
168 ...
169 </screen>
170
171 <para>For instance, every account is usually member in the "Users"
172 group.  All administrator accounts are member of the "Administrators"
173 group.  That's all about it as far as single machines are involved.  In
174 a domain environment it's a bit more tricky.  Since these SIDs are not
175 unique to a machine, every domain user and every domain group can be a
176 member of these well known groups.  Consider the domain group "Domain
177 Admins".  This group is by default in the "Administrators" group.  Let's
178 assume the above computer called "foo" is a member machine of the domain
179 "bar.local".  If you stick the user "BAR\johndoe" into the group "Domain
180 Admins", this guy will automatically be a member of the administrators
181 group on "foo" when logging on to "foo".  Neat, isn't it?</para>
182
183 <para>Back to ACE and ACL.  POSIX is able to create three different
184 permissions, the permissions for the owner, for the group and for the
185 world.  In contrast the Windows ACL has a potentially infinite number of
186 members... as long as they fit into 64K.  Every member is an ACE.
187 ACE consist of three parts:</para>
188
189 <itemizedlist spacing="compact">
190 <listitem><para>The type of the ACE (allow ACE or deny ACE).</para></listitem>
191 <listitem><para>Permission bits, 32 of them.</para></listitem>
192 <listitem><para>The SID for which the permissions are allowed or denied.</para></listitem>
193 </itemizedlist>
194
195 <para>The two (for us) important types of ACEs are the "access allowed
196 ACE" and the "access denied ACE".  As the names imply, the allow ACE
197 tells the system to allow the given permissions to the SID, the deny ACE
198 results in denying the specific permission bits.</para>
199
200 <para>The possible permissions on objects are more detailed than in
201 POSIX.  For example, the permission to delete an object is different
202 from the permission to change object data, and even changing object data
203 can be separated into different permission bits for different kind of
204 data.  But there's a problem with the definition of a "correct" ACL
205 which disallows mapping of certain POSIX permissions cleanly.  See
206 <xref linkend="ntsec-mapping"></xref>.</para>
207
208 <para>POSIX is able to create only three different permissions?  Not quite.
209 Newer operating systems and file systems on POSIX systems also provide
210 access control lists.  Two different APIs exist for accessing these
211 ACLs, the Solaris API and the POSIX API.  Cygwin implements the Solaris
212 API to access Windows ACLs in a Unixy way.  At the time of writing this
213 document, the Cygwin implementation of the Solaris API isn't quite up
214 to speed.  For instance, it doesn't handle access denied ACEs gracefully.
215 So, use with care.  Online man pages for the Solaris ACL API can be
216 found on <ulink url="http://docs.sun.com">http://docs.sun.com</ulink>.</para>
217
218 </sect2>
219
220 <sect2 id="ntsec-files"><title id="ntsec-files.title">File permissions</title>
221
222 <para>On NTFS and if the <literal>noacl</literal> mount option is not
223 specified for a mount point, Cygwin sets file permissions as in POSIX.
224 Basically this is done by defining a SD with the matching owner and group
225 SIDs, and a DACL which contains ACEs for the owner, the group and for
226 "Everyone", which represents what POSIX calls "others".</para>
227
228 <para>To use Windows security correctly, Cygwin depends on the files
229 <filename>/etc/passwd</filename> and <filename>/etc/group</filename>.
230 These files define the translation between the Cygwin uid/gid and the
231 Windows SID.  The SID is stored in the pw_gecos field in
232 <filename>/etc/passwd</filename>, and in the gr_passwd field in
233 <filename>/etc/group</filename>. Since the pw_gecos field can contain
234 more information than just a SID, there are some rules for the layout.
235 It's required that the SID is the last entry of the pw_gecos field,
236 assuming that the entries in pw_gecos are comma-separated.  The
237 commands <command>mkpasswd</command> and <command>mkgroup</command>
238 usually do this for you.</para>
239
240 <para>Another interesting entry in the pw_gecos field (which is also
241 usually created by running <command>mkpasswd</command>) is the Windows user
242 name entry.  It takes the form "U-domain\username" and is sometimes used
243 by services to authenticate a user.  Logging in through
244 <command>telnet</command> is a common scenario.</para>
245
246 <para>A typical snippet from <filename>/etc/passwd</filename>:</para>
247
248 <example id="ntsec-passwd">
249 <title>/etc/passwd:</title>
250 <screen>
251 SYSTEM:*:18:544:,S-1-5-18::
252 Administrators:*:544:544:,S-1-5-32-544::
253 Administrator:unused:500:513:U-FOO\Administrator,S-1-5-21-790525478-115176313-839522115-500:/home/Administrator:/bin/bash
254 corinna:unused:11001:11125:U-BAR\corinna,S-1-5-21-2913048732-1697188782-3448811101-1001:/home/corinna:/bin/tcsh
255 </screen>
256 </example>
257
258 <para>The SYSTEM entry is usually needed by services.  The Administrators
259 entry (Huh?  A group in /etc/passwd?) is only here to allow
260 <command>ls</command> and similar commands to print some file ownerships
261 correctly.  Windows doesn't care if the owner of a file is a user or a
262 group.  In older versions of Windows NT the default ownership for files
263 created by an administrator account was set to the group Administrators
264 instead of to the creating user account.  This has changed, but you can
265 still switch to this setting on newer systems.  So it's convenient to
266 have the Administrators group in
267 <filename>/etc/passwd</filename>.</para>
268
269 <para>The really interesting entries are the next two.  The Administrator
270 entry is for the local administrator, the corinna entry matches the corinna
271 account in the domain BAR.  The information given in the pw_gecos field
272 are all we need to exactly identify an account, and to have a two way
273 translation, from Windows account name/SID to Cygwin account name uid and
274 vice versa.  Having this complete information allows us to choose a Cygwin
275 user name and uid which doesn't have to match the Windows account at all.  As
276 long as the pw_gecos information is available, we're on the safe side:</para>
277
278 <example id="ntsec-passwd-tweaked">
279 <title>/etc/passwd, tweaked:</title>
280 <screen>
281 root:unused:0:513:U-FOO\Administrator,S-1-5-21-790525478-115176313-839522115-500:/home/Administrator:/bin/bash
282 thursday_next:unused:11001:11125:U-BAR\corinna,S-1-5-21-2913048732-1697188782-3448811101-1001:/home/corinna:/bin/tcsh
283 </screen>
284 </example>
285
286 <para>  The above <filename>/etc/passwd</filename> will still work fine.
287 You can now login via <command>ssh</command> as the user "root", and
288 Cygwin dutifully translates "root" into the Windows user
289 "FOO\Administrator" and files owned by FOO\Administrator are shown to
290 have the uid 0 when calling <command>ls -ln</command>.  All you do you're
291 actually doing as Administrator.  Files created as root will be owned by
292 FOO\Administrator.  And the domain user BAR\corinna can now happily
293 pretend to be Thursday Next, but will wake up sooner or later finding
294 out she's still actually the domain user BAR\corinna...</para>
295
296 <para>Do I have to mention that you can also rename groups in
297 <filename>/etc/group</filename>?  As long as the SID is present and correct,
298 all is well.  This allows you to, for instance, rename the "Administrators"
299 group to "root" as well:</para>
300
301 <example id="ntsec-group-tweaked">
302 <title>/etc/group, tweaked:</title>
303 <screen>
304 root:S-1-5-32-544:544:
305 </screen>
306 </example>
307
308 <para>Last but not least, you can also change the primary group of a user
309 in <filename>/etc/passwd</filename>.  The only requirement is that the user
310 is actually a member of the new primary group in Windows.  For instance,
311 normal users in a domain environment are members in the group "Domain Users",
312 which in turn belongs to the well-known group "Users".  So, if it's
313 more convenient in your environment for the user's primary group to be
314 "Users", just set the user's primary group in <filename>/etc/passwd</filename>
315 to the Cygwin uid of "Users" (see in <filename>/etc/group</filename>,
316 default 545) and let the user create files with a default group ownership
317 of "Users".</para>
318
319 <note><para>
320 If you wish to make these kind of changes to /etc/passwd and /etc/group,
321 do so only if you feel comfortable with the concepts.  Otherwise, do not
322 be surprised if things break in either subtle or surprising ways!  If you
323 do screw things up, revert to copies of <filename>/etc/passwd</filename>
324 and <filename>/etc/group</filename> files created by
325 <command>mkpasswd</command> and <command>mkgroup</command>.  (Make
326 backup copies of these files before modifying them.)  Especially, don't
327 change the UID or the name of the user SYSTEM.  It may mostly work, but
328 some Cygwin applications running as a local service under that account
329 could suddenly start behaving strangely.
330 </para></note>
331
332 </sect2>
333
334 <sect2 id="ntsec-ids"><title id="ntsec-ids.title">Special values of user and group ids</title>
335
336 <para>If the current user is not present in
337 <filename>/etc/passwd</filename>, that user's uid is set to a
338 special value of 400.  The user name for the current user will always be
339 shown correctly.  If another user (or a Windows group, treated as a
340 user) is not present in <filename>/etc/passwd</filename>, the uid of
341 that user will have a special value of -1 (which would be shown by
342 <command>ls</command> as 65535).  The user name shown in this case will
343 be '????????'.</para>
344
345 <para>If the current user is not present in
346 <filename>/etc/passwd</filename>, that user's login gid is set to a
347 special value of 401.  The gid 401 is shown as 'mkpasswd',
348 indicating the command that should be run to alleviate the
349 situation.</para>
350
351 <para>If another user is not present in
352 <filename>/etc/passwd</filename>, that user's login gid is set to a
353 special value of -1.  If the user is present in
354 <filename>/etc/passwd</filename>, but that user's group is not in
355 <filename>/etc/group</filename> and is not the login group of that user,
356 the gid is set to a special value of -1.  The name of this group
357 (id -1) will be shown as '????????'.</para>
358
359 <para>If the current user is present in
360 <filename>/etc/passwd</filename>, but that user's login group is not
361 present in <filename>/etc/group</filename>, the group name will be shown
362 as 'mkgroup', again indicating the appropriate command.</para>
363
364 <para>A special case is if the current user's primary group SID is noted
365 in the user's <filename>/etc/passwd</filename> entry using another group
366 id than the group entry of the same group SID in
367 <filename>/etc/group</filename>.  This should be noted and corrected.
368 The group name printed in this case is
369 'passwd/group_GID_clash(PPP/GGG)', with PPP being the gid as noted
370 in <filename>/etc/passwd</filename> and GGG the gid as noted in
371 <filename>/etc/group</filename>.</para>
372
373 <para>To summarize:</para>
374 <itemizedlist spacing="compact">
375
376 <listitem><para>If the current user doesn't show up in
377 <filename>/etc/passwd</filename>, it's <emphasis>group</emphasis> will
378 be named 'mkpasswd'.</para></listitem>
379
380 <listitem><para>Otherwise, if the login group of the current user isn't
381 in <filename>/etc/group</filename>, it will be named 'mkgroup'.</para>
382 </listitem>
383
384 <listitem><para>Otherwise a group not in <filename>/etc/group</filename>
385 will be shown as '????????' and a user not in
386 <filename>/etc/passwd</filename> will be shown as "????????".</para>
387 </listitem>
388
389 <listitem><para>If different group ids are used for a group with the same
390 SID, the group name is shown as 'passwd/group_GID_clash(PPP/GGG)' with
391 PPP and GGG being the different group ids.</para></listitem>
392
393 </itemizedlist>
394
395 <para>
396 Note that, since the special user and group names are just indicators,
397 nothing prevents you from actually having a user named `mkpasswd' in
398 <filename>/etc/passwd</filename> (or a group named `mkgroup' in
399 <filename>/etc/group</filename>).  If you do that, however, be aware of
400 the possible confusion.
401 </para>
402
403 </sect2>
404
405
406 <sect2 id="ntsec-mapping"><title id="ntsec-mapping.title">The POSIX permission mapping leak</title>
407
408 <para>As promised earlier, here's the problem when trying to map the
409 POSIX permission model onto the Windows permission model.</para>
410
411 <para>There's a leak in the definition of a "correct" ACL which
412 disallows a certain POSIX permission setting.  The official
413 documentation explains in short the following:</para>
414
415 <itemizedlist spacing="compact">
416 <listitem><para>The requested permissions are checked against all
417 ACEs of the user as well as all groups the user is member of.  The
418 permissions given in these user and groups access allowed ACEs are
419 accumulated and the resulting set is the set of permissions of that
420 user given for that object.</para></listitem>
421
422 <listitem><para>The order of ACEs is important. The system reads them in
423 sequence until either any single requested permission is denied or all
424 requested permissions are granted.  Reading stops when this condition is
425 met.  Later ACEs are not taken into account.</para></listitem>
426
427 <listitem><para>All access denied ACEs <emphasis
428 role='bold'>should</emphasis> precede any access allowed ACE.  ACLs
429 following this rule are called "canonical"</para></listitem>
430 </itemizedlist>
431
432 <para>Note that the last rule is a preference or a definition of
433 correctness.  It's not an absolute requirement.  All Windows kernels
434 will correctly deal with the ACL regardless of the order of allow and
435 deny ACEs.  The second rule is not modified to get the ACEs in the
436 preferred order.</para>
437
438 <para>Unfortunately the security tab in the file properties dialog of
439 the Windows NT4 explorer is completely unable to deal with access denied ACEs
440 while the Windows 2000 and later properties dialog rearranges the order of the
441 ACEs to canonical order before you can read them. Thank God, the sort
442 order remains unchanged if one presses the Cancel button.  But don't
443 even <emphasis role='bold'>think</emphasis> of pressing OK...</para>
444
445 <para>Canonical ACLs are unable to reflect each possible combination
446 of POSIX permissions. Example:</para>
447
448 <screen>
449 rw-r-xrw-
450 </screen>
451
452 <para>Ok, so here's the first try to create a matching ACL, assuming
453 the Windows permissions only have three bits, as their POSIX counterpart:
454 </para>
455
456 <screen>
457 UserAllow:   110
458 GroupAllow:  101
459 OthersAllow: 110
460 </screen>
461
462 <para>Hmm, because of the accumulation of allow rights the user may
463 execute because the group may execute.</para>
464
465 <para>Second try:</para>
466
467 <screen>
468 UserDeny:    001
469 GroupAllow:  101
470 OthersAllow: 110
471 </screen>
472
473 <para>Now the user may read and write but not execute. Better? No!
474 Unfortunately the group may write now because others may write.</para>
475
476 <para>Third try:</para>
477
478 <screen>
479 UserDeny:    001
480 GroupDeny:   010
481 GroupAllow:  001
482 OthersAllow: 110
483 </screen>
484
485 <para>Now the group may not write as intended but unfortunately the user may
486 not write anymore, either. How should this problem be solved? According to
487 the canonical order a UserAllow has to follow the GroupDeny but it's
488 easy to see that this can never be solved that way.</para>
489
490 <para>The only chance:</para>
491
492 <screen>
493 UserDeny:    001
494 UserAllow:   010
495 GroupDeny:   010
496 GroupAllow:  001
497 OthersAllow: 110
498 </screen>
499
500 <para>Again: This works on all existing versions of Windows NT, at the
501 time of writing from at least NT4 up to Server 2008.  Only the GUIs
502 aren't able (or willing) to deal with that order.</para>
503
504 </sect2>
505
506 <sect2 id="ntsec-setuid-overview"><title id="ntsec-setuid-overview.title">Switching the user context</title>
507
508 <para>Since Windows XP, Windows users have been accustomed to the
509 "Switch User" feature, which switches the entire desktop to another user
510 while leaving the original user's desktop "suspended".  Another Windows
511 feature (since Windows 2000) is the "Run as..." context menu entry,
512 which allows you to start an application using another user account when
513 right-clicking on applications and shortcuts.</para>
514
515 <para>On POSIX systems, this operation can be performed by processes
516 running under the privileged user accounts (usually the "root" user
517 account) on a per-process basis.  This is called "switching the user
518 context" for that process, and is performed using the POSIX
519 <command>setuid</command> and <command>seteuid</command> system
520 calls.</para>
521
522 <para>While this sort of feature is available on Windows as well,
523 Windows does not support the concept of these calls in a simple fashion.
524 Switching the user context in Windows is generally a tricky process with
525 lots of "behind the scenes" magic involved.</para>
526
527 <para>Windows uses so-called `access tokens' to identify a user and its
528 permissions.  Usually the access token is created at logon time and then
529 it's attached to the starting process.  Every new process within a session
530 inherits the access token from its parent process.  Every thread can
531 get its own access token, which allows, for instance, to define threads
532 with restricted permissions.</para>
533
534 </sect2>
535
536 <sect2 id="ntsec-logonuser"><title id="ntsec-logonuser.title">Switching the user context with password authentication</title>
537
538 <para>To switch the user context, the process has to request such an access
539 token for the new user.  This is typically done by calling the Win32 API
540 function <command>LogonUser</command> with the user name and the user's
541 cleartext password as arguments.  If the user exists and the password was
542 specified correctly, the access token is returned and either used in
543 <command>ImpersonateLoggedOnUser</command> to change the user context of
544 the current thread, or in <command>CreateProcessAsUser</command> to
545 change the user context of a spawned child process.</para>
546
547 <para>Later versions of Windows define new functions in this context and
548 there are also functions to manipulate existing access tokens (usually
549 only to restrict them).  Windows Vista also adds subtokens which are
550 attached to other access tokens which plays an important role in the UAC
551 (User Access Control) facility of Vista and later.  However, none of
552 these extensions to the original concept are important for this
553 documentation.</para>
554
555 <para>Back to this logon with password, how can this be used to
556 implement <command>set(e)uid</command>?  Well, it requires modification
557 of the calling application.  Two Cygwin functions have been introduced
558 to support porting <command>setuid</command> applications which only
559 require login with passwords.  You only give Cygwin the right access
560 token and then you can call <command>seteuid</command> or
561 <command>setuid</command> as usual in POSIX applications.  Porting such
562 a <command>setuid</command> application is illustrated by a short
563 example:</para>
564
565 <screen>
566 <![CDATA[
567 /* First include all needed cygwin stuff. */
568 #ifdef __CYGWIN__
569 #include <windows.h>
570 #include <sys/cygwin.h>
571 #endif
572
573 [...]
574
575   struct passwd *user_pwd_entry = getpwnam (username);
576   char *cleartext_password = getpass ("Password:");
577
578 [...]
579
580 #ifdef __CYGWIN__
581   /* Patch the typical password test. */
582   {
583     HANDLE token;
584
585     /* Try to get the access token from Windows. */
586     token = cygwin_logon_user (user_pwd_entry, cleartext_password);
587     if (token == INVALID_HANDLE_VALUE)
588        error_exit;
589     /* Inform Cygwin about the new impersonation token. */
590     cygwin_set_impersonation_token (token);
591     /* Cygwin is now able, to switch to that user context by setuid or seteuid calls. */
592   }
593 #else
594     /* Use standard method on non-Cygwin systems. */
595     hashed_password = crypt (cleartext_password, salt);
596     if (!user_pwd_entry ||
597         strcmp (hashed_password, user_pwd_entry->pw_password))
598       error_exit;
599 #endif /* CYGWIN */
600
601 [...]
602
603   /* Everything else remains the same! */
604
605   setegid (user_pwd_entry->pw_gid);
606   seteuid (user_pwd_entry->pw_uid);
607   execl ("/bin/sh", ...);
608 ]]>
609
610 </screen>
611
612 </sect2>
613
614 <sect2 id="ntsec-nopasswd1"><title id="ntsec-nopasswd1.title">Switching the user context without password, Method 1: Create a token from scratch</title>
615
616 <para>An unfortunate aspect of the implementation of
617 <command>set(e)uid</command> is the fact that the calling process
618 requires the password of the user to which to switch.  Applications such as
619 <command>sshd</command> wishing to switch the user context after a
620 successful public key authentication, or the <command>cron</command>
621 application which, again, wants to switch the user without any authentication
622 are stuck here.  But there are other ways to get new user tokens.</para>
623
624 <para>One way is just to create a user token from scratch.  This is
625 accomplished by using an (officially undocumented) function on the NT
626 function level.  The NT function level is used to implement the Win32
627 level, and, as such is closer to the kernel than the Win32 level.  The
628 function of interest, <command>NtCreateToken</command>, allows you to
629 specify user, groups, permissions and almost everything you need to
630 create a user token, without the need to specify the user password.  The
631 only restriction for using this function is that the calling process
632 needs the "Create a token object" user right, which only the SYSTEM user
633 account has by default, and which is considered the most dangerous right
634 a user can have on Windows systems.</para>
635
636 <para>That sounds good.  We just start the servers which have to switch
637 the user context (<command>sshd</command>, <command>inetd</command>,
638 <command>cron</command>, ...) as Windows services under the SYSTEM
639 (or LocalSystem in the GUI) account and everything just works.
640 Unfortunately that's too simple.  Using <command>NtCreateToken</command>
641 has a few drawbacks.</para>
642
643 <para>First of all, beginning with Windows Server 2003,
644 the permission "Create a token object" gets explicitly removed from
645 the SYSTEM user's access token, when starting services under that
646 account.  That requires us to create a new account with this specific
647 permission just to run this kind of services.  But that's a minor
648 problem.</para>
649
650 <para>A more important problem is that using <command>NtCreateToken</command>
651 is not sufficient to create a new logon session for the new user.  What
652 does that mean?  Every logon usually creates a new logon session.
653 A logon session has a couple of attributes which are unique to the
654 session.  One of these attributes is the fact, that Windows functions
655 identify the user domain and user name not by the SID of the access
656 token owner, but only by the logon session the process is running under.</para>
657
658 <para>This has the following unfortunate consequence.  Consider a
659 service started under the SYSTEM account (up to Windows XP) switches the
660 user context to DOMAIN\my_user using a token created directly by calling
661 the <command>NtCreateToken</command> function.  A process running under
662 this new access token might want to know under which user account it's
663 running.  The corresponding SID is returned correctly, for instance
664 S-1-5-21-1234-5678-9012-77777.  However, if the same process asks the OS
665 for the user name of this SID something wierd happens.  For instance,
666 the <command>LookupAccountSid</command> function will not return
667 "DOMAIN\my_user", but "NT AUTHORITY\SYSTEM" as the user name.</para>
668
669 <para>You might ask "So what?"  After all, this only <emphasis
670 role='bold'>looks</emphasis> bad, but functionality and permission-wise
671 everything should be ok.  And Cygwin knows about this shortcoming so it
672 will return the correct Cygwin username when asked.  Unfortunately this
673 is more complicated.  Some native, non-Cygwin Windows applications will
674 misbehave badly in this situation.  A well-known example are certain versions
675 of Visual-C++.</para>
676
677 <para>Last but not least, you don't have the usual comfortable access
678 to network shares.  The reason is that the token has been created
679 without knowing the password.  The password are your credentials
680 necessary for network access.  Thus, if you logon with a password, the
681 password is stored hidden as "token credentials" within the access token
682 and used as default logon to access network resources.  Since these
683 credentials are missing from the token created with
684 <command>NtCreateToken</command>, you only can access network shares
685 from the new user's process tree by using explicit authentication, on
686 the command line for instance:</para>
687
688 <screen>
689 bash$ net use '\\server\share' /user:DOMAIN\my_user my_users_password
690 </screen>
691
692 <para>Note that, on some systems, you can't even define a drive letter
693 to access the share, and under some circumstances the drive letter you
694 choose collides with a drive letter already used in another session.
695 Therefore it's better to get used to accessing these shares using the UNC
696 path as in</para>
697
698 <screen>
699 bash$ grep foo //server/share/foofile
700 </screen>
701
702 </sect2>
703
704 <sect2 id="ntsec-nopasswd2"><title id="ntsec-nopasswd2.title">Switching the user context without password, Method 2: LSA authentication package</title>
705
706 <para>Caveat: The method described in this chapter only works starting
707 with Windows 2000.  Windows NT4 users have to use one of the other
708 methods described in this document.</para>
709
710 <para>We're looking for another way to switch the user context without
711 having to provide the password.  Another technique is to create an
712 LSA authentication package.  LSA is an acronym for "Local Security Authority"
713 which is a protected part of the operating system which only allows changes
714 to become active when rebooting the system after the change.  Also, as soon as
715 the LSA encounters serious problems (for instance, one of the protected
716 LSA processes died), it triggers a system reboot.  LSA is the part of
717 the OS which cares for the user logons and which also creates logon
718 sessions.</para>
719
720 <para>An LSA authentication package is a DLL which has to be installed
721 as part of the LSA.  This is done by tweaking a special registry key.
722 Cygwin provides such an authentication package.  It has to be installed
723 and the machine has to be rebooted to activate it.  This is the job of the
724 shell script <filename>/usr/bin/cyglsa-config</filename> which is part of
725 the Cygwin package.</para>
726
727 <para>After running <filename>/usr/bin/cyglsa-config</filename> and
728 rebooting the system, the LSA authentication package is used by Cygwin
729 when <command>set(e)uid</command> is called by an application.  The
730 created access token using this method has its own logon session.</para>
731
732 <para>This method has two advantages over the <command>NtCreateToken</command>
733 method.</para>
734
735 <para>The very special and very dangerous "Create a token object" user
736 right is not required by a user using this method.  Other privileged
737 user rights are still necessary, especially the "Act as part of the
738 operating system" right, but that's just business as usual.</para>
739
740 <para>The user is correctly identified, even by delicate native applications
741 which choke on that using the <command>NtCreateToken</command> method.</para>
742
743 <para>Disadvantages?  Yes, sure, this is Windows.  The access token
744 created using LSA authentication still lacks the credentials for network
745 access.  After all, there still hasn't been any password authentication
746 involved.  The requirement to reboot after every installation or
747 deinstallation of the cygwin LSA authentication DLL is just a minor
748 inconvenience compared to that...</para>
749
750 <para>Nevertheless, this is already a lot better than what we get by
751 using <command>NtCreateToken</command>, isn't it?</para>
752
753 </sect2>
754
755 <sect2 id="ntsec-nopasswd3"><title id="ntsec-nopasswd3.title">Switching the user context without password, Method 3: With password</title>
756
757 <para>Ok, so we have solved almost any problem, except for the network
758 access problem.  Not being able to access network shares without
759 having to specify a cleartext password on the command line or in a 
760 script is a harsh problem for automated logons for testing purposes
761 and similar stuff.</para>
762
763 <para>Fortunately there is a solution, but it has its own drawbacks.
764 But, first things first, how does it work?  The title of this section
765 says it all.  Instead of trying to logon without password, we just logon
766 with password.  The password gets stored two-way encrypted in a hidden,
767 obfuscated area of the registry, the LSA private registry area.  This
768 part of the registry contains, for instance, the passwords of the Windows
769 services which run under some non-default user account.</para>
770
771 <para>So what we do is to utilize this registry area for the purpose of
772 <command>set(e)uid</command>.  The Cygwin command <command><link
773 linkend="passwd">passwd</link> -R</command> allows a user to specify
774 his/her password for storage in this registry area.  When this user
775 tries to login using ssh with public key authentication, Cygwin's
776 <command>set(e)uid</command> examines the LSA private registry area and
777 searches for a Cygwin specific key which contains the password.  If it
778 finds it, it calls <command>LogonUser</command> under the hood, using
779 this password.  If that works, <command>LogonUser</command> returns an
780 access token with all credentials necessary for network access.</para>
781
782 <para>For good measure, and since this way to implement
783 <command>set(e)uid</command> is not only used by Cygwin but also by
784 Microsoft's SFU (Services for Unix), we also look for a key stored by
785 SFU (using the SFU command <command>regpwd</command>) and use that if it's
786 available.</para>
787
788 <para>We got it.  A full access token with its own logon session, with
789 all network credentials.  Hmm, that's heaven...</para>
790
791 <para>Back on earth, what about the drawbacks?</para>
792
793 <para>First, adding a password to the LSA private registry area
794 requires administrative access.  So calling <command>passwd -R</command>
795 as a normal user will fail!  Cygwin provides a workaround for
796 this.  If <command>cygserver</command> is started as a service running
797 under the SYSTEM account (which is the default way to run
798 <command>cygserver</command>) you can use <command>passwd -R</command>
799 as normal, non-privileged user as well.</para>
800
801 <para>Second, as aforementioned, the password is two-way encrypted in a
802 hidden, obfuscated registry area.  Only SYSTEM has access to this area
803 for listing purposes, so, even as an administrator, you can't examine
804 this area with regedit.  Right?  No.  Every administrator can start
805 regedit as SYSTEM user:</para>
806
807 <screen>
808 bash$ date
809 Tue Dec  2 16:28:03 CET 2008
810 bash$ at 16:29 /interactive regedit.exe
811 </screen>
812
813 <para>Additionally, if an administrator knows under which name
814 the private key is stored (which is well-known since the algorithms
815 used to create the Cygwin and SFU keys are no secret), every administrator
816 can access the password of all keys stored this way in the registry.</para>
817
818 <para>Conclusion: If your system is used exclusively by you, and if
819 you're also the only administrator of your system, and if your system is
820 adequately locked down to prevent malicious access, you can safely use
821 this method.  If your machine is part of a network which has
822 dedicated administrators, and you're not one of these administrators,
823 but you (think you) can trust your administrators, you can probably
824 safely use this method.</para>
825
826 <para>In all other cases, don't use this method.  You have been warned.</para>
827
828 </sect2>
829
830 <sect2 id="ntsec-setuid-impl"><title id="ntsec-setuid-impl.title">Switching the user context, how does it all fit together?</title>
831
832 <para>Now we learned about four different ways to switch the user
833 context using the <command>set(e)uid</command> system call, but
834 how does <command>set(e)uid</command> really work?  Which method does it
835 use now?</para>
836
837 <para>The answer is, all four of them.  So here's a brief overview
838 what <command>set(e)uid</command> does under the hood:</para>
839
840 <itemizedlist>
841 <listitem>
842 <para>When <command>set(e)uid</command> is called, it tests if the
843 user context had been switched by an earlier call already, and if the
844 new user account is the privileged user account under which the process
845 had been started originally.  If so, it just switches to the original
846 access token of the process it had been started with.</para>
847 </listitem>
848
849 <listitem>
850 <para>
851 Next, it tests if an access token has been stored by an earlier call
852 to <command>cygwin_set_impersonation_token</command>.  If so, it tests
853 if that token matches the requested user account.  If so, the stored
854 token is used for the user context switch.</para>
855
856 <para>
857 If not, there's no predefined token which can just be used for
858 the user context switch, so we have to create a new token.  The order
859 is as follows.</para>
860 </listitem>
861
862 <listitem>
863 <para>Check if the user has stored the logon password in the LSA
864 private registry area, either under a Cygwin key, or under a SFU key.
865 If so, use this to call <command>LogonUser</command>.  If this
866 succeeds, we use the resulting token for the user context switch.</para>
867 </listitem>
868
869 <listitem>
870 <para>Otherwise, check if the Cygwin-specifc LSA authentication package
871 has been installed and is functional.  If so, use the appropriate LSA
872 calls to communicate with the Cygwin LSA authentication package and
873 use the returned token.</para>
874 </listitem>
875
876 <listitem>
877 <para>Last chance, try to use the <command>NtCreateToken</command> call
878 to create a token.  If that works, use this token.</para>
879 </listitem>
880
881 <listitem>
882 <para>If all of the above fails, our process has insufficient privileges
883 to switch the user context at all, so <command>set(e)uid</command>
884 fails and returns -1, setting errno to EPERM.</para>
885 </listitem>
886 </itemizedlist>
887
888 </sect2>
889
890 </sect1>