]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/security.cc
2003-09-15 Pierre Humblet <pierre.humblet@ieee.org>
[newlib-cygwin.git] / winsup / cygwin / security.cc
CommitLineData
1fd5e000
CF
1/* security.cc: NT security functions
2
ab2dbccc 3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
1fd5e000
CF
4
5 Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
fc168ded 6 Completely rewritten by Corinna Vinschen <corinna@vinschen.de>
1fd5e000
CF
7
8This file is part of Cygwin.
9
10This software is a copyrighted work licensed under the terms of the
11Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12details. */
13
4c8d72de 14#include "winsup.h"
1fd5e000
CF
15#include <grp.h>
16#include <pwd.h>
17#include <unistd.h>
18#include <stdlib.h>
1fd5e000
CF
19#include <limits.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <sys/acl.h>
1fd5e000 23#include <ctype.h>
b2939a81 24#include <winnls.h>
ee1d77e4
CF
25#include <wingdi.h>
26#include <winuser.h>
57ff940d
CV
27#include <wininet.h>
28#include <ntsecapi.h>
29#include <subauth.h>
74fcdaec 30#include <aclapi.h>
bccd5e0d 31#include "cygerrno.h"
6b91b8d5 32#include "security.h"
bccd5e0d
CF
33#include "fhandler.h"
34#include "path.h"
e2ebe117
CF
35#include "dtable.h"
36#include "pinfo.h"
1f0f8e12 37#include "cygheap.h"
1fcc912f
CV
38#include <ntdef.h>
39#include "ntdll.h"
40#include "lm.h"
d6ffc075 41#include "pwdgrp.h"
1fcc912f 42
3872e9a4 43bool allow_ntsec;
5827f4d9
CV
44/* allow_smbntsec is handled exclusively in path.cc (path_conv::check).
45 It's defined here because of it's strong relationship to allow_ntsec.
46 The default is TRUE to reflect the old behaviour. */
3872e9a4 47bool allow_smbntsec;
1fd5e000 48
5519d543
CV
49cygsid *
50cygsidlist::alloc_sids (int n)
51{
52 if (n > 0)
53 return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid));
54 else
55 return NULL;
56}
57
58void
59cygsidlist::free_sids ()
60{
61 if (sids)
62 cfree (sids);
5a8746b7
CV
63 sids = NULL;
64 count = maxcount = 0;
65 type = cygsidlist_empty;
5519d543
CV
66}
67
380aaf2d 68extern "C" void
64b30629
CV
69cygwin_set_impersonation_token (const HANDLE hToken)
70{
71 debug_printf ("set_impersonation_token (%d)", hToken);
ea3ba114
CV
72 cygheap->user.external_token = hToken;
73 return;
64b30629
CV
74}
75
1fcc912f 76void
57ff940d
CV
77extract_nt_dom_user (const struct passwd *pw, char *domain, char *user)
78{
c6d90e84 79 char *d, *u, *c;
57ff940d 80
c6d90e84 81 domain[0] = 0;
5519d543 82 strlcpy (user, pw->pw_name, UNLEN + 1);
57ff940d 83 debug_printf ("pw_gecos = %x (%s)", pw->pw_gecos, pw->pw_gecos);
b2939a81 84
c6d90e84
CV
85 if ((d = strstr (pw->pw_gecos, "U-")) != NULL &&
86 (d == pw->pw_gecos || d[-1] == ','))
57ff940d 87 {
0c8455c3
CV
88 c = strechr (d + 2, ',');
89 if ((u = strechr (d + 2, '\\')) >= c)
c6d90e84
CV
90 u = d + 1;
91 else if (u - d <= INTERNET_MAX_HOST_NAME_LENGTH + 2)
5519d543 92 strlcpy (domain, d + 2, u - d - 1);
c6d90e84 93 if (c - u <= UNLEN + 1)
a113a3c5 94 strlcpy (user, u + 1, c - u);
57ff940d 95 }
c6d90e84
CV
96 if (domain[0])
97 return;
98
99 cygsid psid;
100 DWORD ulen = UNLEN + 1;
101 DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
102 SID_NAME_USE use;
103 if (psid.getfrompw (pw))
104 LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use);
57ff940d
CV
105}
106
380aaf2d 107extern "C" HANDLE
64b30629
CV
108cygwin_logon_user (const struct passwd *pw, const char *password)
109{
ba946828 110 if (!wincap.has_security ())
64b30629
CV
111 {
112 set_errno (ENOSYS);
113 return INVALID_HANDLE_VALUE;
114 }
115 if (!pw)
116 {
117 set_errno (EINVAL);
118 return INVALID_HANDLE_VALUE;
119 }
120
57ff940d
CV
121 char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
122 char nt_user[UNLEN + 1];
64b30629
CV
123 HANDLE hToken;
124
57ff940d 125 extract_nt_dom_user (pw, nt_domain, nt_user);
e03f5f73 126 debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password);
57ff940d 127 if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password,
5519d543
CV
128 LOGON32_LOGON_INTERACTIVE,
129 LOGON32_PROVIDER_DEFAULT,
130 &hToken)
64b30629 131 || !SetHandleInformation (hToken,
b0e82b74
CF
132 HANDLE_FLAG_INHERIT,
133 HANDLE_FLAG_INHERIT))
64b30629
CV
134 {
135 __seterrno ();
136 return INVALID_HANDLE_VALUE;
137 }
138 debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name);
139 return hToken;
140}
141
57ff940d
CV
142static void
143str2lsa (LSA_STRING &tgt, const char *srcstr)
144{
1fcc912f 145 tgt.Length = strlen (srcstr);
57ff940d
CV
146 tgt.MaximumLength = tgt.Length + 1;
147 tgt.Buffer = (PCHAR) srcstr;
148}
149
150static void
151str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
152{
1fcc912f 153 tgt.Length = strlen (srcstr);
57ff940d
CV
154 tgt.MaximumLength = tgt.Length + 1;
155 tgt.Buffer = (PCHAR) buf;
03a2ce9a 156 memcpy (buf, srcstr, tgt.MaximumLength);
57ff940d
CV
157}
158
99069065 159void
57ff940d
CV
160str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr)
161{
1fcc912f 162 tgt.Length = strlen (srcstr) * sizeof (WCHAR);
03a2ce9a 163 tgt.MaximumLength = tgt.Length + sizeof (WCHAR);
57ff940d 164 tgt.Buffer = (PWCHAR) buf;
b2939a81 165 sys_mbstowcs (buf, srcstr, tgt.MaximumLength);
57ff940d
CV
166}
167
5519d543 168#if 0 /* unused */
1fcc912f
CV
169static void
170lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size)
171{
172 size = (size - 1) * sizeof (WCHAR);
173 if (src.Length < size)
174 size = src.Length;
175 memcpy (tgt, src.Buffer, size);
176 size >>= 1;
177 tgt[size] = 0;
178}
1eb934b7 179#endif
1fcc912f 180
74b2f73e
CV
181static void
182lsa2str (char *tgt, LSA_UNICODE_STRING &src, int size)
183{
184 if (src.Length / 2 < size)
185 size = src.Length / 2;
186 sys_wcstombs (tgt, src.Buffer, size);
187 tgt[size] = 0;
188}
189
1fcc912f
CV
190static LSA_HANDLE
191open_local_policy ()
192{
193 LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
2d6ce5c2 194 LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
1fcc912f 195
03a2ce9a 196 NTSTATUS ret = LsaOpenPolicy (NULL, &oa, POLICY_EXECUTE, &lsa);
1fcc912f 197 if (ret != STATUS_SUCCESS)
d6dc9825 198 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1fcc912f
CV
199 return lsa;
200}
201
202static void
203close_local_policy (LSA_HANDLE &lsa)
204{
205 if (lsa != INVALID_HANDLE_VALUE)
206 LsaClose (lsa);
207 lsa = INVALID_HANDLE_VALUE;
208}
209
5519d543 210#if 0 /* unused */
1fcc912f
CV
211static BOOL
212get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain)
213{
214 NET_API_STATUS ret;
c8c3824d 215 WCHAR *buf;
1fcc912f
CV
216 char name[INTERNET_MAX_HOST_NAME_LENGTH + 1];
217 WCHAR account[INTERNET_MAX_HOST_NAME_LENGTH + 1];
218 WCHAR primary[INTERNET_MAX_HOST_NAME_LENGTH + 1];
219 PPOLICY_ACCOUNT_DOMAIN_INFO adi;
220 PPOLICY_PRIMARY_DOMAIN_INFO pdi;
221
222 if ((ret = LsaQueryInformationPolicy (lsa, PolicyAccountDomainInformation,
1ff9f4b9 223 (PVOID *) &adi)) != STATUS_SUCCESS)
1fcc912f 224 {
03a2ce9a 225 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1fcc912f
CV
226 return FALSE;
227 }
228 lsa2wchar (account, adi->DomainName, INTERNET_MAX_HOST_NAME_LENGTH + 1);
229 LsaFreeMemory (adi);
230 if ((ret = LsaQueryInformationPolicy (lsa, PolicyPrimaryDomainInformation,
1ff9f4b9 231 (PVOID *) &pdi)) != STATUS_SUCCESS)
1fcc912f 232 {
03a2ce9a 233 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1fcc912f
CV
234 return FALSE;
235 }
236 lsa2wchar (primary, pdi->Name, INTERNET_MAX_HOST_NAME_LENGTH + 1);
237 LsaFreeMemory (pdi);
c8c3824d
CV
238 /* If the SID given in the primary domain info is NULL, the machine is
239 not member of a domain. The name in the primary domain info is the
240 name of the workgroup then. */
241 if (pdi->Sid &&
5519d543
CV
242 (ret =
243 NetGetDCName (NULL, primary, (LPBYTE *) &buf)) == STATUS_SUCCESS)
1fcc912f 244 {
c8c3824d 245 sys_wcstombs (name, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1);
9b15f5fa 246 strcpy (logonserver, name);
1fcc912f 247 if (domain)
1ff9f4b9 248 sys_wcstombs (domain, primary, INTERNET_MAX_HOST_NAME_LENGTH + 1);
1fcc912f
CV
249 }
250 else
251 {
b2939a81 252 sys_wcstombs (name, account, INTERNET_MAX_HOST_NAME_LENGTH + 1);
9b15f5fa
CV
253 strcpy (logonserver, "\\\\");
254 strcat (logonserver, name);
1fcc912f 255 if (domain)
1ff9f4b9 256 sys_wcstombs (domain, account, INTERNET_MAX_HOST_NAME_LENGTH + 1);
1fcc912f
CV
257 }
258 if (ret == STATUS_SUCCESS)
259 NetApiBufferFree (buf);
1fcc912f
CV
260 return TRUE;
261}
1eb934b7 262#endif
1fcc912f
CV
263
264BOOL
5f74ae83 265get_logon_server (const char *domain, char *server, WCHAR *wserver)
1fcc912f 266{
1eb934b7
CV
267 WCHAR wdomain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
268 NET_API_STATUS ret;
44480f46 269 WCHAR *buf;
1eb934b7
CV
270 DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1;
271
891bb974 272 /* Empty domain is interpreted as local system */
5f74ae83 273 if ((GetComputerName (server + 2, &size)) &&
891bb974 274 (strcasematch (domain, server + 2) || !domain[0]))
1fcc912f 275 {
1eb934b7
CV
276 server[0] = server[1] = '\\';
277 if (wserver)
7c02f861 278 sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
1eb934b7 279 return TRUE;
1fcc912f 280 }
1eb934b7
CV
281
282 /* Try to get the primary domain controller for the domain */
283 sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1);
5f74ae83 284 if ((ret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf)) == STATUS_SUCCESS)
1eb934b7
CV
285 {
286 sys_wcstombs (server, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1);
287 if (wserver)
5519d543
CV
288 for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);)
289 ;
1eb934b7
CV
290 NetApiBufferFree (buf);
291 return TRUE;
292 }
293 __seterrno_from_win_error (ret);
294 return FALSE;
1fcc912f
CV
295}
296
297static BOOL
5519d543
CV
298get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user,
299 char *domain)
1fcc912f 300{
1eb934b7 301 char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
462f4eff 302 WCHAR wuser[UNLEN + 1];
b2939a81 303 sys_mbstowcs (wuser, user, UNLEN + 1);
462f4eff 304 LPGROUP_USERS_INFO_0 buf;
1eb934b7 305 DWORD cnt, tot, len;
1fcc912f
CV
306 NET_API_STATUS ret;
307
1eb934b7 308 /* Look only on logonserver */
c9fbce26
CV
309 ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf,
310 MAX_PREFERRED_LENGTH, &cnt, &tot);
c9fbce26 311 if (ret)
1fcc912f 312 {
d6dc9825 313 __seterrno_from_win_error (ret);
1fcc912f
CV
314 /* It's no error when the user name can't be found. */
315 return ret == NERR_UserNotFound;
316 }
317
03a2ce9a
CF
318 len = strlen (domain);
319 strcpy (dgroup, domain);
1eb934b7
CV
320 dgroup[len++] = '\\';
321
1fcc912f
CV
322 for (DWORD i = 0; i < cnt; ++i)
323 {
324 cygsid gsid;
0c8455c3 325 DWORD glen = MAX_SID_LEN;
1fcc912f 326 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
1eb934b7 327 DWORD dlen = sizeof (domain);
1fcc912f
CV
328 SID_NAME_USE use = SidTypeInvalid;
329
1eb934b7
CV
330 sys_wcstombs (dgroup + len, buf[i].grui0_name, GNLEN + 1);
331 if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use))
5519d543 332 debug_printf ("LookupAccountName(%s): %E", dgroup);
1eb934b7 333 else if (legal_sid_type (use))
5519d543
CV
334 grp_list += gsid;
335 else
336 debug_printf ("Global group %s invalid. Domain: %s Use: %d",
337 dgroup, domain, use);
1fcc912f
CV
338 }
339
340 NetApiBufferFree (buf);
341 return TRUE;
342}
343
344static BOOL
1eb934b7 345is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list)
1fcc912f
CV
346{
347 LPLOCALGROUP_MEMBERS_INFO_0 buf;
348 DWORD cnt, tot;
c9fbce26
CV
349 NET_API_STATUS ret;
350 BOOL retval = FALSE;
351
1eb934b7 352 /* Members can be users or global groups */
3d4b75de 353 ret = NetLocalGroupGetMembers (NULL, wgroup, 0, (LPBYTE *) &buf,
c9fbce26 354 MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
c9fbce26 355 if (ret)
1fcc912f
CV
356 return FALSE;
357
c9fbce26 358 for (DWORD bidx = 0; !retval && bidx < cnt; ++bidx)
1eb934b7 359 if (EqualSid (pusersid, buf[bidx].lgrmi0_sid))
c9fbce26 360 retval = TRUE;
1fcc912f 361 else
c9fbce26 362 for (int glidx = 0; !retval && glidx < grp_list.count; ++glidx)
1fcc912f 363 if (EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi0_sid))
c9fbce26 364 retval = TRUE;
1fcc912f
CV
365
366 NetApiBufferFree (buf);
c9fbce26 367 return retval;
1fcc912f
CV
368}
369
370static BOOL
1eb934b7 371get_user_local_groups (cygsidlist &grp_list, PSID pusersid)
1fcc912f
CV
372{
373 LPLOCALGROUP_INFO_0 buf;
374 DWORD cnt, tot;
375 NET_API_STATUS ret;
376
3d4b75de 377 ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf,
c9fbce26 378 MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
c9fbce26 379 if (ret)
1fcc912f 380 {
d6dc9825 381 __seterrno_from_win_error (ret);
1fcc912f
CV
382 return FALSE;
383 }
384
6e8a0232 385 char bgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
1eb934b7 386 char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
6e8a0232
CV
387 DWORD blen, llen;
388 SID_NAME_USE use;
389
390 blen = llen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
391 if (!LookupAccountSid (NULL, well_known_admins_sid, lgroup, &llen, bgroup, &blen, &use)
392 || !GetComputerNameA (lgroup, &(llen = INTERNET_MAX_HOST_NAME_LENGTH + 1)))
1eb934b7 393 {
5519d543
CV
394 __seterrno ();
395 return FALSE;
1eb934b7 396 }
6e8a0232 397 bgroup[blen++] = lgroup[llen++] = '\\';
1eb934b7 398
1fcc912f 399 for (DWORD i = 0; i < cnt; ++i)
1eb934b7 400 if (is_group_member (buf[i].lgrpi0_name, pusersid, grp_list))
1fcc912f
CV
401 {
402 cygsid gsid;
0c8455c3 403 DWORD glen = MAX_SID_LEN;
1fcc912f 404 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
1eb934b7 405 DWORD dlen = sizeof (domain);
1fcc912f 406
6e8a0232 407 use = SidTypeInvalid;
1eb934b7
CV
408 sys_wcstombs (bgroup + blen, buf[i].lgrpi0_name, GNLEN + 1);
409 if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use))
1fcc912f 410 {
095a1272 411 if (GetLastError () != ERROR_NONE_MAPPED)
5519d543 412 debug_printf ("LookupAccountName(%s): %E", bgroup);
095a1272
CV
413 strcpy (lgroup + llen, bgroup + blen);
414 if (!LookupAccountName (NULL, lgroup, gsid, &glen,
415 domain, &dlen, &use))
5519d543 416 debug_printf ("LookupAccountName(%s): %E", lgroup);
1fcc912f 417 }
095a1272
CV
418 if (!legal_sid_type (use))
419 debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use);
420 else if (!grp_list.contains (gsid))
1fcc912f
CV
421 grp_list += gsid;
422 }
1fcc912f
CV
423 NetApiBufferFree (buf);
424 return TRUE;
425}
426
427static BOOL
428sid_in_token_groups (PTOKEN_GROUPS grps, cygsid &sid)
429{
430 if (!grps)
431 return FALSE;
432 for (DWORD i = 0; i < grps->GroupCount; ++i)
433 if (sid == grps->Groups[i].Sid)
434 return TRUE;
435 return FALSE;
436}
437
5519d543 438#if 0 /* Unused */
1fcc912f
CV
439static BOOL
440get_user_primary_group (WCHAR *wlogonserver, const char *user,
1eb934b7 441 PSID pusersid, cygsid &pgrpsid)
1fcc912f
CV
442{
443 LPUSER_INFO_3 buf;
444 WCHAR wuser[UNLEN + 1];
c9fbce26
CV
445 NET_API_STATUS ret;
446 BOOL retval = FALSE;
8b43d272 447 UCHAR count = 0;
1fcc912f 448
dbcb7578 449 if (well_known_system_sid == pusersid)
1fcc912f
CV
450 {
451 pgrpsid = well_known_system_sid;
452 return TRUE;
453 }
454
b2939a81 455 sys_mbstowcs (wuser, user, UNLEN + 1);
c9fbce26 456 ret = NetUserGetInfo (wlogonserver, wuser, 3, (LPBYTE *) &buf);
c9fbce26
CV
457 if (ret)
458 {
d6dc9825 459 __seterrno_from_win_error (ret);
c9fbce26
CV
460 return FALSE;
461 }
462
1eb934b7 463 pgrpsid = pusersid;
5519d543
CV
464 if (IsValidSid (pgrpsid)
465 && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1)
1fcc912f
CV
466 {
467 *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id;
c9fbce26 468 retval = TRUE;
1fcc912f
CV
469 }
470 NetApiBufferFree (buf);
c9fbce26 471 return retval;
1fcc912f 472}
095a1272 473#endif
1fcc912f 474
095a1272 475static void
44480f46 476get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
f41d24a1 477{
57196405 478 struct __group32 *gr;
095a1272 479 cygsid gsid;
f41d24a1
CV
480
481 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
482 {
095a1272
CV
483 if (gr->gr_gid == (__gid32_t) pw->pw_gid)
484 goto found;
485 else if (gr->gr_mem)
f41d24a1 486 for (int gi = 0; gr->gr_mem[gi]; ++gi)
095a1272
CV
487 if (strcasematch (pw->pw_name, gr->gr_mem[gi]))
488 goto found;
489 continue;
490 found:
491 if (gsid.getfromgr (gr) && !grp_list.contains (gsid))
492 grp_list += gsid;
493
f41d24a1 494 }
f41d24a1
CV
495}
496
5519d543
CV
497static void
498get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
499 LUID auth_luid, int &auth_pos)
1fcc912f 500{
1fcc912f 501 auth_pos = -1;
5519d543
CV
502 if (my_grps)
503 {
504 if (sid_in_token_groups (my_grps, well_known_local_sid))
505 grp_list += well_known_local_sid;
506 if (sid_in_token_groups (my_grps, well_known_dialup_sid))
507 grp_list += well_known_dialup_sid;
508 if (sid_in_token_groups (my_grps, well_known_network_sid))
509 grp_list += well_known_network_sid;
510 if (sid_in_token_groups (my_grps, well_known_batch_sid))
511 grp_list += well_known_batch_sid;
512 if (sid_in_token_groups (my_grps, well_known_interactive_sid))
513 grp_list += well_known_interactive_sid;
514 if (sid_in_token_groups (my_grps, well_known_service_sid))
515 grp_list += well_known_service_sid;
516 }
517 else
518 {
519 grp_list += well_known_local_sid;
520 grp_list += well_known_interactive_sid;
521 }
522 if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */
523 {
524 char buf[64];
525 __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart,
526 auth_luid.LowPart);
527 grp_list += buf;
528 auth_pos = grp_list.count - 1;
529 }
530}
1eb934b7 531
5519d543
CV
532static BOOL
533get_initgroups_sidlist (cygsidlist &grp_list,
534 PSID usersid, PSID pgrpsid, struct passwd *pw,
535 PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos,
536 BOOL &special_pgrp)
537{
1fcc912f 538 grp_list += well_known_world_sid;
095a1272 539 grp_list += well_known_authenticated_users_sid;
dbcb7578 540 if (well_known_system_sid == usersid)
1fcc912f 541 {
5519d543 542 auth_pos = -1;
3a157c0d 543 grp_list += well_known_admins_sid;
095a1272 544 get_unix_group_sidlist (pw, grp_list);
1fcc912f
CV
545 }
546 else
547 {
5519d543
CV
548 char user[UNLEN + 1];
549 char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
550 WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3];
551 char server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
552
553 get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos);
095a1272 554 extract_nt_dom_user (pw, domain, user);
fdb93cd2
CV
555 if (get_logon_server (domain, server, wserver))
556 get_user_groups (wserver, grp_list, user, domain);
095a1272
CV
557 get_unix_group_sidlist (pw, grp_list);
558 if (!get_user_local_groups (grp_list, usersid))
7c02f861 559 return FALSE;
1fcc912f 560 }
5519d543
CV
561 /* special_pgrp true if pgrpsid is not in normal groups */
562 if ((special_pgrp = !grp_list.contains (pgrpsid)))
563 grp_list += pgrpsid;
1fcc912f
CV
564 return TRUE;
565}
566
5519d543
CV
567static void
568get_setgroups_sidlist (cygsidlist &tmp_list, PTOKEN_GROUPS my_grps,
569 user_groups &groups, LUID auth_luid, int &auth_pos)
570{
571 PSID pgpsid = groups.pgsid;
572 tmp_list += well_known_world_sid;
573 tmp_list += well_known_authenticated_users_sid;
574 get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos);
575 for (int gidx = 0; gidx < groups.sgsids.count; gidx++)
576 tmp_list += groups.sgsids.sids[gidx];
577 if (!groups.sgsids.contains (pgpsid))
578 tmp_list += pgpsid;
579}
580
1fcc912f
CV
581static const char *sys_privs[] = {
582 SE_TCB_NAME,
583 SE_ASSIGNPRIMARYTOKEN_NAME,
584 SE_CREATE_TOKEN_NAME,
585 SE_CHANGE_NOTIFY_NAME,
586 SE_SECURITY_NAME,
587 SE_BACKUP_NAME,
588 SE_RESTORE_NAME,
589 SE_SYSTEMTIME_NAME,
590 SE_SHUTDOWN_NAME,
591 SE_REMOTE_SHUTDOWN_NAME,
592 SE_TAKE_OWNERSHIP_NAME,
593 SE_DEBUG_NAME,
594 SE_SYSTEM_ENVIRONMENT_NAME,
595 SE_SYSTEM_PROFILE_NAME,
596 SE_PROF_SINGLE_PROCESS_NAME,
597 SE_INC_BASE_PRIORITY_NAME,
598 SE_LOAD_DRIVER_NAME,
599 SE_CREATE_PAGEFILE_NAME,
600 SE_INCREASE_QUOTA_NAME
601};
602
603#define SYSTEM_PERMISSION_COUNT (sizeof sys_privs / sizeof (const char *))
604
605PTOKEN_PRIVILEGES
606get_system_priv_list (cygsidlist &grp_list)
607{
608 LUID priv;
5519d543
CV
609 PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES)
610 malloc (sizeof (ULONG) + 20 * sizeof (LUID_AND_ATTRIBUTES));
1fcc912f
CV
611 if (!privs)
612 {
613 debug_printf ("malloc (system_privs) failed.");
614 return NULL;
615 }
616 privs->PrivilegeCount = 0;
617
618 for (DWORD i = 0; i < SYSTEM_PERMISSION_COUNT; ++i)
619 if (LookupPrivilegeValue (NULL, sys_privs[i], &priv))
620 {
621 privs->Privileges[privs->PrivilegeCount].Luid = priv;
622 privs->Privileges[privs->PrivilegeCount].Attributes =
5519d543 623 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
1fcc912f
CV
624 ++privs->PrivilegeCount;
625 }
626 return privs;
627}
628
629PTOKEN_PRIVILEGES
630get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
631{
632 PLSA_UNICODE_STRING privstrs;
633 ULONG cnt;
634 PTOKEN_PRIVILEGES privs = NULL;
635 NTSTATUS ret;
636 char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
637
638 if (usersid == well_known_system_sid)
639 return get_system_priv_list (grp_list);
640
641 for (int grp = -1; grp < grp_list.count; ++grp)
642 {
643 if (grp == -1)
1ff9f4b9 644 {
5519d543
CV
645 if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs,
646 &cnt)) != STATUS_SUCCESS)
1ff9f4b9
CF
647 continue;
648 }
1fcc912f 649 else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
1ff9f4b9
CF
650 &privstrs, &cnt))
651 != STATUS_SUCCESS)
1fcc912f
CV
652 continue;
653 for (ULONG i = 0; i < cnt; ++i)
1ff9f4b9
CF
654 {
655 LUID priv;
656 PTOKEN_PRIVILEGES tmp;
657 DWORD tmp_count;
658
03a2ce9a 659 lsa2str (buf, privstrs[i], sizeof (buf) - 1);
1ff9f4b9
CF
660 if (!LookupPrivilegeValue (NULL, buf, &priv))
661 continue;
662
663 for (DWORD p = 0; privs && p < privs->PrivilegeCount; ++p)
664 if (!memcmp (&priv, &privs->Privileges[p].Luid, sizeof (LUID)))
665 goto next_account_right;
666
667 tmp_count = privs ? privs->PrivilegeCount : 0;
668 tmp = (PTOKEN_PRIVILEGES)
5519d543
CV
669 realloc (privs, sizeof (ULONG) +
670 (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES));
1ff9f4b9
CF
671 if (!tmp)
672 {
1fcc912f
CV
673 if (privs)
674 free (privs);
1ff9f4b9 675 LsaFreeMemory (privstrs);
1fcc912f 676 debug_printf ("realloc (privs) failed.");
1ff9f4b9
CF
677 return NULL;
678 }
679 tmp->PrivilegeCount = tmp_count;
680 privs = tmp;
681 privs->Privileges[privs->PrivilegeCount].Luid = priv;
682 privs->Privileges[privs->PrivilegeCount].Attributes =
5519d543 683 SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
1ff9f4b9
CF
684 ++privs->PrivilegeCount;
685
686 next_account_right:
687 ;
688 }
1fcc912f
CV
689 LsaFreeMemory (privstrs);
690 }
691 return privs;
692}
693
5519d543
CV
694/* Accept a token if
695 - the requested usersid matches the TokenUser and
696 - if setgroups has been called:
5bf785a0 697 the token groups that are listed in /etc/group match the union of
5519d543
CV
698 the requested primary and supplementary groups in gsids.
699 - else the (unknown) implicitly requested supplementary groups and those
5bf785a0 700 in the token are the groups associated with the usersid. We assume
5519d543
CV
701 they match and verify only the primary groups.
702 The requested primary group must appear in the token.
703 The primary group in the token is a group associated with the usersid,
704 except if the token is internal and the group is in the token SD
705 (see create_token). In that latter case that group must match the
706 requested primary group. */
ebbdc703 707BOOL
5519d543 708verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL *pintern)
1fcc912f 709{
ebbdc703
CV
710 DWORD size;
711 BOOL intern = FALSE;
712
713 if (pintern)
714 {
715 TOKEN_SOURCE ts;
70249d56 716 if (!GetTokenInformation (token, TokenSource,
ebbdc703
CV
717 &ts, sizeof ts, &size))
718 debug_printf ("GetTokenInformation(): %E");
5519d543
CV
719 else
720 *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
ebbdc703
CV
721 }
722 /* Verify usersid */
723 cygsid tok_usersid = NO_SID;
724 if (!GetTokenInformation (token, TokenUser,
725 &tok_usersid, sizeof tok_usersid, &size))
5519d543
CV
726 debug_printf ("GetTokenInformation(): %E");
727 if (usersid != tok_usersid)
728 return FALSE;
ebbdc703 729
5519d543
CV
730 /* For an internal token, if setgroups was not called and if the sd group
731 is not well_known_null_sid, it must match pgrpsid */
732 if (intern && !groups.issetgroups ())
ebbdc703 733 {
5519d543 734 char sd_buf[MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR)];
ea3ba114 735 cygpsid gsid (NO_SID);
5519d543 736 if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION,
ebbdc703
CV
737 (PSECURITY_DESCRIPTOR) sd_buf,
738 sizeof sd_buf, &size))
5519d543
CV
739 debug_printf ("GetKernelObjectSecurity(): %E");
740 else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) sd_buf,
ea3ba114 741 (PSID *) &gsid, (BOOL *) &size))
5519d543
CV
742 debug_printf ("GetSecurityDescriptorGroup(): %E");
743 if (well_known_null_sid != gsid)
744 return gsid == groups.pgsid;
ebbdc703 745 }
5519d543 746
b4ece40c
PH
747 PTOKEN_GROUPS my_grps;
748 bool saw_buf[NGROUPS_MAX] = {};
749 bool *saw = saw_buf, sawpg = false, ret = false;
ebbdc703
CV
750
751 if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) &&
03a2ce9a 752 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
f70389b5 753 debug_printf ("GetTokenInformation(token, TokenGroups): %E");
b4ece40c
PH
754 else if (!(my_grps = (PTOKEN_GROUPS) alloca (size)))
755 debug_printf ("alloca (my_grps) failed.");
ebbdc703 756 else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size))
f70389b5 757 debug_printf ("GetTokenInformation(my_token, TokenGroups): %E");
5519d543 758 else if (!groups.issetgroups ()) /* setgroups was never called */
b4ece40c 759 ret = sid_in_token_groups (my_grps, groups.pgsid)
df04ae29 760 || groups.pgsid == usersid;
5519d543
CV
761 else /* setgroups was called */
762 {
763 struct __group32 *gr;
764 cygsid gsid;
b4ece40c
PH
765 if (groups.sgsids.count > (int) (sizeof (saw_buf) / sizeof (*saw_buf))
766 && !(saw = (bool *) calloc (groups.sgsids.count, sizeof (bool))))
5519d543
CV
767 goto done;
768
769 /* token groups found in /etc/group match the user.gsids ? */
770 for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
771 if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid))
772 {
773 int pos = groups.sgsids.position (gsid);
774 if (pos >= 0)
b4ece40c 775 saw[pos] = true;
5519d543 776 else if (groups.pgsid == gsid)
b4ece40c
PH
777 sawpg = true;
778 else if (gsid != well_known_world_sid
779 && gsid != usersid)
5519d543
CV
780 goto done;
781 }
782 for (int gidx = 0; gidx < groups.sgsids.count; gidx++)
783 if (!saw[gidx])
784 goto done;
b4ece40c
PH
785 ret = sawpg
786 || groups.sgsids.contains (groups.pgsid)
787 || groups.pgsid == usersid;
5519d543
CV
788 }
789done:
5519d543
CV
790 if (saw != saw_buf)
791 free (saw);
ebbdc703 792 return ret;
1fcc912f
CV
793}
794
795HANDLE
5519d543 796create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
1fcc912f
CV
797{
798 NTSTATUS ret;
2d6ce5c2 799 LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
1fcc912f
CV
800 int old_priv_state;
801
5519d543 802 cygsidlist tmp_gsids (cygsidlist_auto, 12);
1fcc912f
CV
803
804 SECURITY_QUALITY_OF_SERVICE sqos =
805 { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
5519d543 806 OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos };
ebbdc703 807 PSECURITY_ATTRIBUTES psa;
5519d543 808 BOOL special_pgrp = FALSE;
f6fc31e1 809 char sa_buf[1024];
1fcc912f 810 LUID auth_luid = SYSTEM_LUID;
5519d543 811 LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL };
1fcc912f
CV
812
813 TOKEN_USER user;
5519d543 814 PTOKEN_GROUPS new_tok_gsids = NULL;
1fcc912f
CV
815 PTOKEN_PRIVILEGES privs = NULL;
816 TOKEN_OWNER owner;
817 TOKEN_PRIMARY_GROUP pgrp;
5519d543 818 char acl_buf[MAX_DACL_LEN (5)];
1fcc912f
CV
819 TOKEN_DEFAULT_DACL dacl;
820 TOKEN_SOURCE source;
821 TOKEN_STATISTICS stats;
03a2ce9a 822 memcpy (source.SourceName, "Cygwin.1", 8);
1fcc912f
CV
823 source.SourceIdentifier.HighPart = 0;
824 source.SourceIdentifier.LowPart = 0x0101;
825
cecb74ae 826 HANDLE token = INVALID_HANDLE_VALUE;
1fcc912f
CV
827 HANDLE primary_token = INVALID_HANDLE_VALUE;
828
829 HANDLE my_token = INVALID_HANDLE_VALUE;
5519d543 830 PTOKEN_GROUPS my_tok_gsids = NULL;
1fcc912f
CV
831 DWORD size;
832
833 /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
834 if ((old_priv_state = set_process_privilege (SE_CREATE_TOKEN_NAME)) < 0)
835 goto out;
1ff9f4b9 836
1fcc912f 837 /* Open policy object. */
2d6ce5c2 838 if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
1fcc912f
CV
839 goto out;
840
1fcc912f
CV
841 /* User, owner, primary group. */
842 user.User.Sid = usersid;
843 user.User.Attributes = 0;
844 owner.Owner = usersid;
845
846 /* Retrieve authentication id and group list from own process. */
03a2ce9a 847 if (!OpenProcessToken (hMainProc, TOKEN_QUERY, &my_token))
f70389b5 848 debug_printf ("OpenProcessToken(my_token): %E");
1fcc912f
CV
849 else
850 {
851 /* Switching user context to SYSTEM doesn't inherit the authentication
5bf785a0 852 id of the user account running current process. */
1fcc912f
CV
853 if (usersid != well_known_system_sid)
854 if (!GetTokenInformation (my_token, TokenStatistics,
855 &stats, sizeof stats, &size))
5519d543 856 debug_printf
f70389b5 857 ("GetTokenInformation(my_token, TokenStatistics): %E");
1fcc912f
CV
858 else
859 auth_luid = stats.AuthenticationId;
860
861 /* Retrieving current processes group list to be able to inherit
5bf785a0 862 some important well known group sids. */
1fcc912f 863 if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) &&
462f4eff 864 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
f70389b5 865 debug_printf ("GetTokenInformation(my_token, TokenGroups): %E");
5519d543
CV
866 else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
867 debug_printf ("malloc (my_tok_gsids) failed.");
868 else if (!GetTokenInformation (my_token, TokenGroups, my_tok_gsids,
1fcc912f
CV
869 size, &size))
870 {
f70389b5 871 debug_printf ("GetTokenInformation(my_token, TokenGroups): %E");
5519d543
CV
872 free (my_tok_gsids);
873 my_tok_gsids = NULL;
1fcc912f 874 }
2d3dab2e 875 CloseHandle (my_token);
1fcc912f
CV
876 }
877
878 /* Create list of groups, the user is member in. */
879 int auth_pos;
5519d543
CV
880 if (new_groups.issetgroups ())
881 get_setgroups_sidlist (tmp_gsids, my_tok_gsids, new_groups, auth_luid,
882 auth_pos);
883 else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
884 my_tok_gsids, auth_luid, auth_pos,
885 special_pgrp))
1fcc912f
CV
886 goto out;
887
888 /* Primary group. */
5519d543 889 pgrp.PrimaryGroup = new_groups.pgsid;
1fcc912f
CV
890
891 /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
5519d543
CV
892 char grps_buf[sizeof (ULONG) + tmp_gsids.count * sizeof (SID_AND_ATTRIBUTES)];
893 new_tok_gsids = (PTOKEN_GROUPS) grps_buf;
894 new_tok_gsids->GroupCount = tmp_gsids.count;
895 for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
1fcc912f 896 {
5519d543
CV
897 new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
898 new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY |
899 SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
1fcc912f 900 }
5519d543
CV
901 if (auth_pos >= 0)
902 new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
1fcc912f
CV
903
904 /* Retrieve list of privileges of that user. */
5519d543 905 if (!(privs = get_priv_list (lsa, usersid, tmp_gsids)))
1fcc912f
CV
906 goto out;
907
908 /* Create default dacl. */
c61ada9b 909 if (!sec_acl ((PACL) acl_buf, false, false,
5519d543
CV
910 tmp_gsids.contains (well_known_admins_sid) ?
911 well_known_admins_sid : usersid))
1fcc912f
CV
912 goto out;
913 dacl.DefaultDacl = (PACL) acl_buf;
914
915 /* Let's be heroic... */
916 ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
5519d543
CV
917 &auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
918 &pgrp, &dacl, &source);
1fcc912f 919 if (ret)
d6dc9825 920 __seterrno_from_win_error (RtlNtStatusToDosError (ret));
1fcc912f
CV
921 else if (GetLastError () == ERROR_PROC_NOT_FOUND)
922 {
923 __seterrno ();
924 debug_printf ("Loading NtCreateToken failed.");
925 }
ebbdc703
CV
926 else
927 {
928 /* Set security descriptor and primary group */
c61ada9b 929 psa = sec_user (sa_buf, usersid);
2402700d 930 if (psa->lpSecurityDescriptor &&
5519d543
CV
931 !SetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR)
932 psa->lpSecurityDescriptor,
933 special_pgrp ? new_groups.pgsid
934 : well_known_null_sid,
935 FALSE))
936 debug_printf ("SetSecurityDescriptorGroup %E");
ebbdc703 937 /* Convert to primary token. */
5519d543
CV
938 if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa, SecurityImpersonation,
939 TokenPrimary, &primary_token))
2402700d
CF
940 {
941 __seterrno ();
942 debug_printf ("DuplicateTokenEx %E");
943 }
ebbdc703 944 }
1fcc912f
CV
945
946out:
947 if (old_priv_state >= 0)
948 set_process_privilege (SE_CREATE_TOKEN_NAME, old_priv_state);
949 if (token != INVALID_HANDLE_VALUE)
950 CloseHandle (token);
951 if (privs)
952 free (privs);
5519d543
CV
953 if (my_tok_gsids)
954 free (my_tok_gsids);
1fcc912f
CV
955 close_local_policy (lsa);
956
957 debug_printf ("%d = create_token ()", primary_token);
958 return primary_token;
959}
960
57ff940d
CV
961int subauth_id = 255;
962
963HANDLE
964subauth (struct passwd *pw)
965{
966 LSA_STRING name;
967 HANDLE lsa_hdl;
968 LSA_OPERATIONAL_MODE sec_mode;
969 NTSTATUS ret, ret2;
970 ULONG package_id, size;
971 struct {
972 LSA_STRING str;
973 CHAR buf[16];
974 } origin;
975 struct {
976 MSV1_0_LM20_LOGON auth;
977 WCHAR dombuf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
978 WCHAR usrbuf[UNLEN + 1];
979 WCHAR wkstbuf[1];
980 CHAR authinf1[1];
981 CHAR authinf2[1];
982 } subbuf;
983 TOKEN_SOURCE ts;
984 PMSV1_0_LM20_LOGON_PROFILE profile;
985 LUID luid;
57ff940d
CV
986 QUOTA_LIMITS quota;
987 char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
988 char nt_user[UNLEN + 1];
1fcc912f
CV
989 SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE };
990 HANDLE user_token = INVALID_HANDLE_VALUE;
991 HANDLE primary_token = INVALID_HANDLE_VALUE;
992 int old_tcb_state;
57ff940d 993
03a2ce9a 994 if ((old_tcb_state = set_process_privilege (SE_TCB_NAME)) < 0)
1fcc912f 995 return INVALID_HANDLE_VALUE;
57ff940d
CV
996
997 /* Register as logon process. */
998 str2lsa (name, "Cygwin");
a2cdb048 999 SetLastError (0);
03a2ce9a 1000 ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
57ff940d
CV
1001 if (ret != STATUS_SUCCESS)
1002 {
1003 debug_printf ("LsaRegisterLogonProcess: %d", ret);
03a2ce9a 1004 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1fcc912f 1005 goto out;
57ff940d 1006 }
5aac6665
CV
1007 else if (GetLastError () == ERROR_PROC_NOT_FOUND)
1008 {
1009 debug_printf ("Couldn't load Secur32.dll");
1fcc912f 1010 goto out;
5aac6665 1011 }
57ff940d
CV
1012 /* Get handle to MSV1_0 package. */
1013 str2lsa (name, MSV1_0_PACKAGE_NAME);
03a2ce9a 1014 ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
57ff940d
CV
1015 if (ret != STATUS_SUCCESS)
1016 {
1017 debug_printf ("LsaLookupAuthenticationPackage: %d", ret);
03a2ce9a
CF
1018 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1019 LsaDeregisterLogonProcess (lsa_hdl);
1fcc912f 1020 goto out;
57ff940d
CV
1021 }
1022 /* Create origin. */
1023 str2buf2lsa (origin.str, origin.buf, "Cygwin");
1024 /* Create token source. */
03a2ce9a 1025 memcpy (ts.SourceName, "Cygwin.1", 8);
42938841
CV
1026 ts.SourceIdentifier.HighPart = 0;
1027 ts.SourceIdentifier.LowPart = 0x0100;
57ff940d
CV
1028 /* Get user information. */
1029 extract_nt_dom_user (pw, nt_domain, nt_user);
1030 /* Fill subauth with values. */
1031 subbuf.auth.MessageType = MsV1_0NetworkLogon;
03a2ce9a
CF
1032 str2buf2uni (subbuf.auth.LogonDomainName, subbuf.dombuf, nt_domain);
1033 str2buf2uni (subbuf.auth.UserName, subbuf.usrbuf, nt_user);
1034 str2buf2uni (subbuf.auth.Workstation, subbuf.wkstbuf, "");
1035 memcpy (subbuf.auth.ChallengeToClient, "12345678", MSV1_0_CHALLENGE_LENGTH);
1036 str2buf2lsa (subbuf.auth.CaseSensitiveChallengeResponse, subbuf.authinf1, "");
5519d543 1037 str2buf2lsa (subbuf.auth.CaseInsensitiveChallengeResponse,subbuf.authinf2,"");
57ff940d
CV
1038 subbuf.auth.ParameterControl = 0 | (subauth_id << 24);
1039 /* Try to logon... */
03a2ce9a 1040 ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Network,
5519d543
CV
1041 package_id, &subbuf, sizeof subbuf,
1042 NULL, &ts, (PVOID *) &profile, &size,
1043 &luid, &user_token, &quota, &ret2);
57ff940d
CV
1044 if (ret != STATUS_SUCCESS)
1045 {
1046 debug_printf ("LsaLogonUser: %d", ret);
03a2ce9a
CF
1047 __seterrno_from_win_error (LsaNtStatusToWinError (ret));
1048 LsaDeregisterLogonProcess (lsa_hdl);
1fcc912f 1049 goto out;
57ff940d 1050 }
03a2ce9a 1051 LsaFreeReturnBuffer (profile);
57ff940d 1052 /* Convert to primary token. */
57ff940d 1053 if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa,
5519d543 1054 SecurityImpersonation, TokenPrimary, &primary_token))
1fcc912f
CV
1055 __seterrno ();
1056
1057out:
03a2ce9a 1058 set_process_privilege (SE_TCB_NAME, old_tcb_state);
1fcc912f
CV
1059 if (user_token != INVALID_HANDLE_VALUE)
1060 CloseHandle (user_token);
57ff940d
CV
1061 return primary_token;
1062}
1063
d6581f44 1064/* read_sd reads a security descriptor from a file.
1fd5e000 1065 In case of error, -1 is returned and errno is set.
dd67f9db
CV
1066 If sd_buf is too small, 0 is returned and sd_size
1067 is set to the needed buffer size.
1068 On success, 1 is returned.
1069
1070 GetFileSecurity() is used instead of BackupRead()
1071 to avoid access denied errors if the caller has
1072 not the permission to open that file for read.
1073
1074 Originally the function should return the size
1075 of the SD on success. Unfortunately NT returns
1076 0 in `len' on success, while W2K returns the
1077 correct size!
1fd5e000
CF
1078*/
1079
1080LONG
03a2ce9a 1081read_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size)
1fd5e000
CF
1082{
1083 /* Check parameters */
2a6fc028 1084 if (!sd_size)
1fd5e000
CF
1085 {
1086 set_errno (EINVAL);
1087 return -1;
1088 }
1089
03a2ce9a 1090 debug_printf ("file = %s", file);
1fd5e000 1091
d6581f44 1092 DWORD len = 0;
ee1d77e4 1093 const char *pfile = file;
5519d543 1094 char fbuf[PATH_MAX];
ee1d77e4
CF
1095 if (current_codepage == oem_cp)
1096 {
1097 DWORD fname_len = min (sizeof (fbuf) - 1, strlen (file));
1098 bzero (fbuf, sizeof (fbuf));
03a2ce9a 1099 OemToCharBuff (file, fbuf, fname_len);
ee1d77e4
CF
1100 pfile = fbuf;
1101 }
1102
2a6fc028 1103 if (!GetFileSecurity (pfile,
462f4eff 1104 OWNER_SECURITY_INFORMATION
5519d543
CV
1105 | GROUP_SECURITY_INFORMATION
1106 | DACL_SECURITY_INFORMATION,
1107 sd_buf, *sd_size, &len))
1fd5e000
CF
1108 {
1109 __seterrno ();
1110 return -1;
1111 }
03a2ce9a 1112 debug_printf ("file = %s: len=%d", file, len);
d6581f44 1113 if (len > *sd_size)
1fd5e000 1114 {
d6581f44
CV
1115 *sd_size = len;
1116 return 0;
1fd5e000 1117 }
dd67f9db 1118 return 1;
1fd5e000
CF
1119}
1120
1121LONG
03a2ce9a 1122write_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size)
1fd5e000
CF
1123{
1124 /* Check parameters */
2a6fc028 1125 if (!sd_buf || !sd_size)
1fd5e000
CF
1126 {
1127 set_errno (EINVAL);
1128 return -1;
1129 }
1130
62cd433e
CV
1131 BOOL dummy;
1132 cygpsid owner;
1133
1134 if (!GetSecurityDescriptorOwner (sd_buf, (PSID *) &owner, &dummy))
1135 {
1136 __seterrno ();
1137 return -1;
1138 }
1139 /* Try turning privilege on, may not have WRITE_OWNER or WRITE_DAC access.
1140 Must have privilege to set different owner, else BackupWrite misbehaves */
1141 static int NO_COPY saved_res; /* 0: never, 1: failed, 2 & 3: OK */
1142 int res;
1143 if (!saved_res || cygheap->user.issetuid ())
1144 {
1145 res = 2 + set_process_privilege (SE_RESTORE_NAME, true,
1146 cygheap->user.issetuid ());
1147 if (!cygheap->user.issetuid ())
1148 saved_res = res;
1149 }
1150 else
1151 res = saved_res;
1152 if (res == 1 && owner != cygheap->user.sid ())
1153 return -1;
1154
d6581f44
CV
1155 HANDLE fh;
1156 fh = CreateFile (file,
b0e82b74
CF
1157 WRITE_OWNER | WRITE_DAC,
1158 FILE_SHARE_READ | FILE_SHARE_WRITE,
1159 &sec_none_nih,
1160 OPEN_EXISTING,
1161 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
1162 NULL);
1fd5e000 1163
d6581f44 1164 if (fh == INVALID_HANDLE_VALUE)
1fd5e000
CF
1165 {
1166 __seterrno ();
1167 return -1;
1168 }
1169
1170 LPVOID context = NULL;
1171 DWORD bytes_written = 0;
1172 WIN32_STREAM_ID header;
1173
1174 memset (&header, 0, sizeof (header));
1175 /* write new security info header */
1176 header.dwStreamId = BACKUP_SECURITY_DATA;
1177 header.dwStreamAttributes = STREAM_CONTAINS_SECURITY;
1178 header.Size.HighPart = 0;
d6581f44 1179 header.Size.LowPart = sd_size;
1fd5e000 1180 header.dwStreamNameSize = 0;
d6581f44 1181 if (!BackupWrite (fh, (LPBYTE) &header,
1fd5e000
CF
1182 3 * sizeof (DWORD) + sizeof (LARGE_INTEGER),
1183 &bytes_written, FALSE, TRUE, &context))
1184 {
1185 __seterrno ();
d6581f44 1186 CloseHandle (fh);
1fd5e000
CF
1187 return -1;
1188 }
1189
1190 /* write new security descriptor */
d6581f44 1191 if (!BackupWrite (fh, (LPBYTE) sd_buf,
1fd5e000
CF
1192 header.Size.LowPart + header.dwStreamNameSize,
1193 &bytes_written, FALSE, TRUE, &context))
1194 {
1195 /* Samba returns ERROR_NOT_SUPPORTED.
5bf785a0
CF
1196 FAT returns ERROR_INVALID_SECURITY_DESCR.
1197 This shouldn't return as error, but better be ignored. */
1fd5e000
CF
1198 DWORD ret = GetLastError ();
1199 if (ret != ERROR_NOT_SUPPORTED && ret != ERROR_INVALID_SECURITY_DESCR)
1200 {
1201 __seterrno ();
d6581f44
CV
1202 BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context);
1203 CloseHandle (fh);
1fd5e000
CF
1204 return -1;
1205 }
1206 }
1207
1208 /* terminate the restore process */
d6581f44
CV
1209 BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context);
1210 CloseHandle (fh);
1fd5e000
CF
1211 return 0;
1212}
1213
38170b13 1214static void
407b8df6 1215get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid,
c90e1cf1 1216 PSID group_sid, BOOL grp_member)
38170b13
CV
1217{
1218 ACCESS_ALLOWED_ACE *ace;
1219 int allow = 0;
1220 int deny = 0;
1221 int *flags, *anti;
1222
1223 for (DWORD i = 0; i < acl->AceCount; ++i)
1224 {
1225 if (!GetAce (acl, i, (PVOID *) &ace))
1226 continue;
1227 if (ace->Header.AceFlags & INHERIT_ONLY)
1228 continue;
1229 switch (ace->Header.AceType)
1230 {
1231 case ACCESS_ALLOWED_ACE_TYPE:
1232 flags = &allow;
1233 anti = &deny;
1234 break;
1235 case ACCESS_DENIED_ACE_TYPE:
1236 flags = &deny;
1237 anti = &allow;
1238 break;
1239 default:
1240 continue;
1241 }
1242
0c8455c3 1243 cygpsid ace_sid ((PSID) &ace->SidStart);
38170b13
CV
1244 if (ace_sid == well_known_world_sid)
1245 {
1246 if (ace->Mask & FILE_READ_DATA)
dbcb7578 1247 *flags |= ((!(*anti & S_IROTH)) ? S_IROTH : 0)
38170b13
CV
1248 | ((!(*anti & S_IRGRP)) ? S_IRGRP : 0)
1249 | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0);
1250 if (ace->Mask & FILE_WRITE_DATA)
dbcb7578 1251 *flags |= ((!(*anti & S_IWOTH)) ? S_IWOTH : 0)
38170b13
CV
1252 | ((!(*anti & S_IWGRP)) ? S_IWGRP : 0)
1253 | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0);
1254 if (ace->Mask & FILE_EXECUTE)
dbcb7578 1255 *flags |= ((!(*anti & S_IXOTH)) ? S_IXOTH : 0)
9a751621
CF
1256 | ((!(*anti & S_IXGRP)) ? S_IXGRP : 0)
1257 | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0);
b1897d27 1258 if ((S_ISDIR (*attribute)) &&
38170b13
CV
1259 (ace->Mask & (FILE_WRITE_DATA | FILE_EXECUTE | FILE_DELETE_CHILD))
1260 == (FILE_WRITE_DATA | FILE_EXECUTE))
1261 *flags |= S_ISVTX;
1262 }
1263 else if (ace_sid == well_known_null_sid)
1264 {
1265 /* Read SUID, SGID and VTX bits from NULL ACE. */
1266 if (ace->Mask & FILE_READ_DATA)
1267 *flags |= S_ISVTX;
1268 if (ace->Mask & FILE_WRITE_DATA)
1269 *flags |= S_ISGID;
1270 if (ace->Mask & FILE_APPEND_DATA)
1271 *flags |= S_ISUID;
1272 }
dbcb7578 1273 else if (ace_sid == owner_sid)
38170b13
CV
1274 {
1275 if (ace->Mask & FILE_READ_DATA)
dbcb7578 1276 *flags |= ((!(*anti & S_IRUSR)) ? S_IRUSR : 0);
38170b13 1277 if (ace->Mask & FILE_WRITE_DATA)
dbcb7578 1278 *flags |= ((!(*anti & S_IWUSR)) ? S_IWUSR : 0);
38170b13 1279 if (ace->Mask & FILE_EXECUTE)
dbcb7578 1280 *flags |= ((!(*anti & S_IXUSR)) ? S_IXUSR : 0);
38170b13 1281 }
dbcb7578 1282 else if (ace_sid == group_sid)
38170b13
CV
1283 {
1284 if (ace->Mask & FILE_READ_DATA)
dbcb7578 1285 *flags |= ((!(*anti & S_IRGRP)) ? S_IRGRP : 0)
38170b13
CV
1286 | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0);
1287 if (ace->Mask & FILE_WRITE_DATA)
dbcb7578 1288 *flags |= ((!(*anti & S_IWGRP)) ? S_IWGRP : 0)
38170b13
CV
1289 | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0);
1290 if (ace->Mask & FILE_EXECUTE)
dbcb7578 1291 *flags |= ((!(*anti & S_IXGRP)) ? S_IXGRP : 0)
38170b13
CV
1292 | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0);
1293 }
1294 }
1295 *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID);
dbcb7578
CV
1296 if (owner_sid && group_sid && EqualSid (owner_sid, group_sid)
1297 /* FIXME: temporary exception for /var/empty */
1298 && well_known_system_sid != group_sid)
1299 {
1300 allow &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
1301 allow |= (((allow & S_IRUSR) ? S_IRGRP : 0)
1302 | ((allow & S_IWUSR) ? S_IWGRP : 0)
1303 | ((allow & S_IXUSR) ? S_IXGRP : 0));
1304 }
38170b13 1305 *attribute |= allow;
38170b13
CV
1306 return;
1307}
1308
2e23862a
CV
1309static void
1310get_info_from_sd (PSECURITY_DESCRIPTOR psd, mode_t *attribute,
a8d7ae61 1311 __uid32_t *uidret, __gid32_t *gidret)
1fd5e000 1312{
2e23862a 1313 if (!psd)
1fd5e000 1314 {
2e23862a
CV
1315 /* If reading the security descriptor failed, treat the object
1316 as unreadable. */
1317 if (attribute)
1318 *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
1319 if (uidret)
1320 *uidret = ILLEGAL_UID;
1321 if (gidret)
1322 *gidret = ILLEGAL_GID;
1323 return;
1fd5e000
CF
1324 }
1325
0c8455c3
CV
1326 cygpsid owner_sid;
1327 cygpsid group_sid;
1fd5e000
CF
1328 BOOL dummy;
1329
0c8455c3 1330 if (!GetSecurityDescriptorOwner (psd, (PSID *) &owner_sid, &dummy))
1fd5e000 1331 debug_printf ("GetSecurityDescriptorOwner %E");
0c8455c3 1332 if (!GetSecurityDescriptorGroup (psd, (PSID *) &group_sid, &dummy))
1fd5e000
CF
1333 debug_printf ("GetSecurityDescriptorGroup %E");
1334
0c8455c3
CV
1335 __uid32_t uid;
1336 __gid32_t gid;
1337 BOOL grp_member = get_sids_info (owner_sid, group_sid, &uid, &gid);
5d4af61e
CV
1338 if (uidret)
1339 *uidret = uid;
1340 if (gidret)
1341 *gidret = gid;
1342
2a6fc028 1343 if (!attribute)
5d4af61e 1344 {
2e23862a
CV
1345 syscall_printf ("uid %d, gid %d", uid, gid);
1346 return;
5d4af61e
CV
1347 }
1348
2e23862a
CV
1349 PACL acl;
1350 BOOL acl_exists;
1351
1352 if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy))
1fd5e000 1353 {
2e23862a
CV
1354 __seterrno ();
1355 debug_printf ("GetSecurityDescriptorDacl %E");
1356 *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
1fd5e000 1357 }
2e23862a
CV
1358 else if (!acl_exists || !acl)
1359 *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
1360 else
1361 get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member);
1fd5e000 1362
2e23862a
CV
1363 syscall_printf ("%sACL = %x, uid %d, gid %d",
1364 (!acl_exists || !acl)?"NO ":"", *attribute, uid, gid);
1365 return;
1366}
1367
1368static void
1369get_nt_attribute (const char *file, mode_t *attribute,
1370 __uid32_t *uidret, __gid32_t *gidret)
1371{
1372 /* Yeah, sounds too much, but I've seen SDs of 2100 bytes! */
1373 DWORD sd_size = 4096;
1374 char sd_buf[4096];
1375 PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf;
1376
1377 if (read_sd (file, psd, &sd_size) <= 0)
1378 {
1379 debug_printf ("read_sd %E");
1380 psd = NULL;
1381 }
1382
1383 get_info_from_sd (psd, attribute, uidret, gidret);
1384 return;
1fd5e000
CF
1385}
1386
1387int
d6581f44 1388get_file_attribute (int use_ntsec, const char *file,
407b8df6 1389 mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret)
1fd5e000 1390{
10b06c5e 1391 int res;
2e23862a 1392 syscall_printf ("file: %s", file);
10b06c5e 1393
2d388e43 1394 if (use_ntsec && allow_ntsec && wincap.has_security ())
10b06c5e 1395 {
2e23862a 1396 get_nt_attribute (file, attribute, uidret, gidret);
3eb27a4e 1397 return 0;
10b06c5e 1398 }
1fd5e000 1399
5d4af61e 1400 if (uidret)
ea3ba114 1401 *uidret = myself->uid;
5d4af61e 1402 if (gidret)
ea3ba114 1403 *gidret = myself->gid;
1fd5e000 1404
2a6fc028 1405 if (!attribute)
5d4af61e 1406 return 0;
1fd5e000 1407
149da470
ED
1408 if (allow_ntea)
1409 {
1410 int oatt = *attribute;
c90e1cf1 1411 res = NTReadEA (file, ".UNIXATTR", (char *)attribute, sizeof (*attribute));
149da470
ED
1412 *attribute |= oatt;
1413 }
1414 else
1415 res = 0;
1fd5e000 1416
5d4af61e 1417 return res > 0 ? 0 : -1;
1fd5e000
CF
1418}
1419
2e23862a 1420static void
5519d543 1421get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type,
407b8df6 1422 mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret)
74fcdaec 1423{
2e23862a
CV
1424 PSECURITY_DESCRIPTOR psd;
1425 char sd_buf[4096];
74fcdaec 1426
98b36ec8 1427 if (object_type == SE_REGISTRY_KEY)
5519d543 1428 {
2e23862a
CV
1429 /* use different code for registry handles, for performance reasons */
1430 psd = (PSECURITY_DESCRIPTOR) & sd_buf[0];
98b36ec8
CV
1431 DWORD len = sizeof (sd_buf);
1432 if (ERROR_SUCCESS != RegGetKeySecurity ((HKEY) handle,
df04ae29
CF
1433 DACL_SECURITY_INFORMATION |
1434 GROUP_SECURITY_INFORMATION |
1435 OWNER_SECURITY_INFORMATION,
1436 psd, &len))
1437 {
1438 __seterrno ();
1439 debug_printf ("RegGetKeySecurity %E");
1440 psd = NULL;
1441 }
2e23862a 1442 }
98b36ec8
CV
1443 else
1444 {
1445 if (ERROR_SUCCESS != GetSecurityInfo (handle, object_type,
2e23862a
CV
1446 DACL_SECURITY_INFORMATION |
1447 GROUP_SECURITY_INFORMATION |
1448 OWNER_SECURITY_INFORMATION,
1449 NULL, NULL, NULL, NULL, &psd))
df04ae29 1450 {
2e23862a
CV
1451 __seterrno ();
1452 debug_printf ("GetSecurityInfo %E");
1453 psd = NULL;
1454 }
74fcdaec
CF
1455 }
1456
2e23862a
CV
1457 get_info_from_sd (psd, attribute, uidret, gidret);
1458 if (psd != (PSECURITY_DESCRIPTOR) & sd_buf[0])
1459 LocalFree (psd);
74fcdaec 1460
2e23862a 1461 return;
74fcdaec
CF
1462}
1463
1464int
1465get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type,
407b8df6 1466 mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret)
74fcdaec 1467{
2d388e43 1468 if (allow_ntsec && wincap.has_security ())
74fcdaec 1469 {
2e23862a
CV
1470 get_nt_object_attribute (handle, object_type, attribute, uidret, gidret);
1471 return 0;
74fcdaec 1472 }
2e23862a
CV
1473 /* The entries are already set to default values */
1474 return -1;
74fcdaec
CF
1475}
1476
c0d1968a
CV
1477BOOL
1478add_access_allowed_ace (PACL acl, int offset, DWORD attributes,
1479 PSID sid, size_t &len_add, DWORD inherit)
1fd5e000 1480{
2a6fc028 1481 if (!AddAccessAllowedAce (acl, ACL_REVISION, attributes, sid))
1fd5e000
CF
1482 {
1483 __seterrno ();
1484 return FALSE;
1485 }
1486 ACCESS_ALLOWED_ACE *ace;
dbcb7578 1487 if (inherit && GetAce (acl, offset, (PVOID *) &ace))
1fd5e000 1488 ace->Header.AceFlags |= inherit;
dbcb7578 1489 len_add += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + GetLengthSid (sid);
1fd5e000
CF
1490 return TRUE;
1491}
1492
c0d1968a
CV
1493BOOL
1494add_access_denied_ace (PACL acl, int offset, DWORD attributes,
1495 PSID sid, size_t &len_add, DWORD inherit)
1fd5e000 1496{
2a6fc028 1497 if (!AddAccessDeniedAce (acl, ACL_REVISION, attributes, sid))
1fd5e000
CF
1498 {
1499 __seterrno ();
1500 return FALSE;
1501 }
1502 ACCESS_DENIED_ACE *ace;
dbcb7578 1503 if (inherit && GetAce (acl, offset, (PVOID *) &ace))
1fd5e000 1504 ace->Header.AceFlags |= inherit;
5519d543 1505 len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid);
1fd5e000
CF
1506 return TRUE;
1507}
1508
1509PSECURITY_DESCRIPTOR
2e8abfc1 1510alloc_sd (__uid32_t uid, __gid32_t gid, int attribute,
1fd5e000
CF
1511 PSECURITY_DESCRIPTOR sd_ret, DWORD *sd_size_ret)
1512{
1513 BOOL dummy;
1514
dbcb7578 1515 debug_printf("uid %d, gid %d, attribute %x", uid, gid, attribute);
2a6fc028 1516 if (!sd_ret || !sd_size_ret)
1fd5e000
CF
1517 {
1518 set_errno (EINVAL);
1519 return NULL;
1520 }
1521
dbcb7578
CV
1522 /* Get owner and group from current security descriptor. */
1523 PSID cur_owner_sid = NULL;
1524 PSID cur_group_sid = NULL;
1525 if (!GetSecurityDescriptorOwner (sd_ret, &cur_owner_sid, &dummy))
1526 debug_printf ("GetSecurityDescriptorOwner %E");
1527 if (!GetSecurityDescriptorGroup (sd_ret, &cur_group_sid, &dummy))
1528 debug_printf ("GetSecurityDescriptorGroup %E");
1529
dd0208eb 1530 /* Get SID of owner. */
ab2dbccc 1531 cygsid owner_sid;
dd0208eb
CV
1532 /* Check for current user first */
1533 if (uid == myself->uid)
1534 owner_sid = cygheap->user.sid ();
dbcb7578
CV
1535 else if (uid == ILLEGAL_UID)
1536 owner_sid = cur_owner_sid;
d6ffc075 1537 else if (!owner_sid.getfrompw (internal_getpwuid (uid)))
dd0208eb 1538 {
dbcb7578
CV
1539 set_errno (EINVAL);
1540 return NULL;
dd0208eb
CV
1541 }
1542 owner_sid.debug_print ("alloc_sd: owner SID =");
1fd5e000 1543
dd0208eb 1544 /* Get SID of new group. */
ab2dbccc 1545 cygsid group_sid;
329b9ead
CF
1546 /* Check for current user first */
1547 if (gid == myself->gid)
1548 group_sid = cygheap->user.groups.pgsid;
dbcb7578
CV
1549 else if (gid == ILLEGAL_GID)
1550 group_sid = cur_group_sid;
d6ffc075 1551 else if (!group_sid.getfromgr (internal_getgrgid (gid)))
dbcb7578
CV
1552 {
1553 set_errno (EINVAL);
1554 return NULL;
1555 }
1556 group_sid.debug_print ("alloc_sd: group SID =");
1557
c434bd08 1558 /* Initialize local security descriptor. */
1fd5e000 1559 SECURITY_DESCRIPTOR sd;
2a6fc028 1560 if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
1fd5e000
CF
1561 {
1562 __seterrno ();
1563 return NULL;
1564 }
1565
aa2b85cc 1566 /*
b2652452
CV
1567 * We set the SE_DACL_PROTECTED flag here to prevent the DACL from being
1568 * modified by inheritable ACEs.
1569 * This flag as well as the SetSecurityDescriptorControl call are available
1570 * only since Win2K.
aa2b85cc 1571 */
ba946828 1572 if (wincap.has_security_descriptor_control ())
aa2b85cc
CV
1573 SetSecurityDescriptorControl (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
1574
c434bd08 1575 /* Create owner for local security descriptor. */
03a2ce9a 1576 if (!SetSecurityDescriptorOwner (&sd, owner_sid, FALSE))
1fd5e000
CF
1577 {
1578 __seterrno ();
1579 return NULL;
1580 }
c434bd08
CV
1581
1582 /* Create group for local security descriptor. */
dbcb7578 1583 if (!SetSecurityDescriptorGroup (&sd, group_sid, FALSE))
1fd5e000
CF
1584 {
1585 __seterrno ();
1586 return NULL;
1587 }
1588
c434bd08 1589 /* Initialize local access control list. */
1fd5e000
CF
1590 char acl_buf[3072];
1591 PACL acl = (PACL) acl_buf;
2a6fc028 1592 if (!InitializeAcl (acl, 3072, ACL_REVISION))
1fd5e000
CF
1593 {
1594 __seterrno ();
1595 return NULL;
1596 }
1597
c434bd08 1598 /* From here fill ACL. */
1fd5e000
CF
1599 size_t acl_len = sizeof (ACL);
1600 int ace_off = 0;
1601
c434bd08 1602 /* Construct allow attribute for owner. */
556ceaeb 1603 DWORD owner_allow = STANDARD_RIGHTS_ALL
b0e82b74 1604 | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA;
1fd5e000
CF
1605 if (attribute & S_IRUSR)
1606 owner_allow |= FILE_GENERIC_READ;
1607 if (attribute & S_IWUSR)
556ceaeb 1608 owner_allow |= FILE_GENERIC_WRITE;
1fd5e000
CF
1609 if (attribute & S_IXUSR)
1610 owner_allow |= FILE_GENERIC_EXECUTE;
b1897d27
CV
1611 if (S_ISDIR (attribute)
1612 && (attribute & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR))
1fd5e000
CF
1613 owner_allow |= FILE_DELETE_CHILD;
1614
c434bd08 1615 /* Construct allow attribute for group. */
1fd5e000 1616 DWORD group_allow = STANDARD_RIGHTS_READ
b0e82b74 1617 | FILE_READ_ATTRIBUTES | FILE_READ_EA;
1fd5e000
CF
1618 if (attribute & S_IRGRP)
1619 group_allow |= FILE_GENERIC_READ;
1620 if (attribute & S_IWGRP)
3a157c0d 1621 group_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE;
1fd5e000
CF
1622 if (attribute & S_IXGRP)
1623 group_allow |= FILE_GENERIC_EXECUTE;
b1897d27
CV
1624 if (S_ISDIR (attribute)
1625 && (attribute & (S_IWGRP | S_IXGRP)) == (S_IWGRP | S_IXGRP)
1626 && !(attribute & S_ISVTX))
1fd5e000
CF
1627 group_allow |= FILE_DELETE_CHILD;
1628
c434bd08 1629 /* Construct allow attribute for everyone. */
1fd5e000 1630 DWORD other_allow = STANDARD_RIGHTS_READ
b0e82b74 1631 | FILE_READ_ATTRIBUTES | FILE_READ_EA;
1fd5e000
CF
1632 if (attribute & S_IROTH)
1633 other_allow |= FILE_GENERIC_READ;
1634 if (attribute & S_IWOTH)
3a157c0d 1635 other_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE;
1fd5e000
CF
1636 if (attribute & S_IXOTH)
1637 other_allow |= FILE_GENERIC_EXECUTE;
b1897d27
CV
1638 if (S_ISDIR (attribute)
1639 && (attribute & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH)
3a157c0d 1640 && !(attribute & S_ISVTX))
1fd5e000 1641 other_allow |= FILE_DELETE_CHILD;
75a57bf0 1642
3a157c0d
CV
1643 /* Construct SUID, SGID and VTX bits in NULL ACE. */
1644 DWORD null_allow = 0L;
1645 if (attribute & (S_ISUID | S_ISGID | S_ISVTX))
1646 {
1647 if (attribute & S_ISUID)
1ff9f4b9 1648 null_allow |= FILE_APPEND_DATA;
3a157c0d 1649 if (attribute & S_ISGID)
1ff9f4b9 1650 null_allow |= FILE_WRITE_DATA;
3a157c0d 1651 if (attribute & S_ISVTX)
1ff9f4b9 1652 null_allow |= FILE_READ_DATA;
3a157c0d
CV
1653 }
1654
dbcb7578
CV
1655 /* Add owner and group permissions if SIDs are equal
1656 and construct deny attributes for group and owner. */
ab2dbccc
CV
1657 BOOL isownergroup;
1658 if ((isownergroup = (owner_sid == group_sid)))
1659 owner_allow |= group_allow;
1660
dbcb7578 1661 DWORD owner_deny = ~owner_allow & (group_allow | other_allow);
1fd5e000 1662 owner_deny &= ~(STANDARD_RIGHTS_READ
b0e82b74
CF
1663 | FILE_READ_ATTRIBUTES | FILE_READ_EA
1664 | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA);
1fd5e000 1665
ab2dbccc
CV
1666 DWORD group_deny = ~group_allow & other_allow;
1667 group_deny &= ~(STANDARD_RIGHTS_READ
1668 | FILE_READ_ATTRIBUTES | FILE_READ_EA);
154110f5 1669
c434bd08 1670 /* Set deny ACE for owner. */
1fd5e000 1671 if (owner_deny
2a6fc028 1672 && !add_access_denied_ace (acl, ace_off++, owner_deny,
ab2dbccc 1673 owner_sid, acl_len, NO_INHERITANCE))
3a157c0d 1674 return NULL;
dbcb7578
CV
1675 /* Set deny ACE for group here to respect the canonical order,
1676 if this does not impact owner */
ab2dbccc
CV
1677 if (group_deny && !(group_deny & owner_allow) && !isownergroup
1678 && !add_access_denied_ace (acl, ace_off++, group_deny,
1679 group_sid, acl_len, NO_INHERITANCE))
1680 return NULL;
c434bd08 1681 /* Set allow ACE for owner. */
2a6fc028 1682 if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
ab2dbccc 1683 owner_sid, acl_len, NO_INHERITANCE))
1fd5e000 1684 return NULL;
dbcb7578 1685 /* Set deny ACE for group, if still needed. */
ab2dbccc 1686 if (group_deny & owner_allow && !isownergroup
2a6fc028 1687 && !add_access_denied_ace (acl, ace_off++, group_deny,
ab2dbccc 1688 group_sid, acl_len, NO_INHERITANCE))
3a157c0d 1689 return NULL;
c434bd08 1690 /* Set allow ACE for group. */
ab2dbccc 1691 if (!isownergroup
dbcb7578 1692 && !add_access_allowed_ace (acl, ace_off++, group_allow,
ab2dbccc 1693 group_sid, acl_len, NO_INHERITANCE))
1fd5e000
CF
1694 return NULL;
1695
22ae5a5b
CV
1696 /* Set allow ACE for everyone. */
1697 if (!add_access_allowed_ace (acl, ace_off++, other_allow,
ab2dbccc 1698 well_known_world_sid, acl_len, NO_INHERITANCE))
22ae5a5b 1699 return NULL;
3a157c0d
CV
1700 /* Set null ACE for special bits. */
1701 if (null_allow
1702 && !add_access_allowed_ace (acl, ace_off++, null_allow,
654bad37 1703 well_known_null_sid, acl_len, NO_INHERITANCE))
3a157c0d 1704 return NULL;
22ae5a5b 1705
c434bd08 1706 /* Fill ACL with unrelated ACEs from current security descriptor. */
1fd5e000 1707 PACL oacl;
ab2dbccc 1708 BOOL acl_exists = FALSE;
1fd5e000
CF
1709 ACCESS_ALLOWED_ACE *ace;
1710 if (GetSecurityDescriptorDacl (sd_ret, &acl_exists, &oacl, &dummy)
1711 && acl_exists && oacl)
1712 for (DWORD i = 0; i < oacl->AceCount; ++i)
1713 if (GetAce (oacl, i, (PVOID *) &ace))
b0e82b74 1714 {
0c8455c3
CV
1715 cygpsid ace_sid ((PSID) &ace->SidStart);
1716
c434bd08 1717 /* Check for related ACEs. */
ab2dbccc
CV
1718 if (ace_sid == well_known_null_sid)
1719 continue;
dbcb7578
CV
1720 if ((ace_sid == cur_owner_sid)
1721 || (ace_sid == owner_sid)
1722 || (ace_sid == cur_group_sid)
1723 || (ace_sid == group_sid)
ab2dbccc
CV
1724 || (ace_sid == well_known_world_sid))
1725 {
1726 if (ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
1727 ace->Header.AceFlags |= INHERIT_ONLY;
1728 else
1729 continue;
1730 }
c434bd08
CV
1731 /*
1732 * Add unrelated ACCESS_DENIED_ACE to the beginning but
22ae5a5b 1733 * behind the owner_deny, ACCESS_ALLOWED_ACE to the end.
ab2dbccc 1734 * FIXME: this would break the order of the inherit_only ACEs
c434bd08 1735 */
03a2ce9a 1736 if (!AddAce (acl, ACL_REVISION,
ab2dbccc 1737 ace->Header.AceType == ACCESS_DENIED_ACE_TYPE?
b0e82b74
CF
1738 (owner_deny ? 1 : 0) : MAXDWORD,
1739 (LPVOID) ace, ace->Header.AceSize))
1740 {
1741 __seterrno ();
1742 return NULL;
1743 }
1744 acl_len += ace->Header.AceSize;
b0e82b74 1745 }
1fd5e000 1746
ab2dbccc 1747 /* Construct appropriate inherit attribute for new directories */
b1897d27 1748 if (S_ISDIR (attribute) && !acl_exists )
ab2dbccc
CV
1749 {
1750 const DWORD inherit = SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY;
1751
1752#if 0 /* FIXME: Not done currently as this breaks the canonical order */
1753 /* Set deny ACE for owner. */
1754 if (owner_deny
1755 && !add_access_denied_ace (acl, ace_off++, owner_deny,
1756 well_known_creator_owner_sid, acl_len, inherit))
1757 return NULL;
1758 /* Set deny ACE for group here to respect the canonical order,
1759 if this does not impact owner */
1760 if (group_deny && !(group_deny & owner_allow)
1761 && !add_access_denied_ace (acl, ace_off++, group_deny,
1762 well_known_creator_group_sid, acl_len, inherit))
1763 return NULL;
1764#endif
1765 /* Set allow ACE for owner. */
1766 if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
1767 well_known_creator_owner_sid, acl_len, inherit))
1768 return NULL;
1769#if 0 /* FIXME: Not done currently as this breaks the canonical order and
1770 won't be preserved on chown and chmod */
1771 /* Set deny ACE for group, conflicting with owner_allow. */
1772 if (group_deny & owner_allow
1773 && !add_access_denied_ace (acl, ace_off++, group_deny,
1774 well_known_creator_group_sid, acl_len, inherit))
1775 return NULL;
1776#endif
1777 /* Set allow ACE for group. */
1778 if (!add_access_allowed_ace (acl, ace_off++, group_allow,
1779 well_known_creator_group_sid, acl_len, inherit))
1780 return NULL;
1781 /* Set allow ACE for everyone. */
1782 if (!add_access_allowed_ace (acl, ace_off++, other_allow,
1783 well_known_world_sid, acl_len, inherit))
1784 return NULL;
1785 }
1786
c434bd08 1787 /* Set AclSize to computed value. */
1fd5e000
CF
1788 acl->AclSize = acl_len;
1789 debug_printf ("ACL-Size: %d", acl_len);
1790
c434bd08 1791 /* Create DACL for local security descriptor. */
2a6fc028 1792 if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE))
1fd5e000
CF
1793 {
1794 __seterrno ();
1795 return NULL;
1796 }
1797
c434bd08 1798 /* Make self relative security descriptor. */
1fd5e000
CF
1799 *sd_size_ret = 0;
1800 MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret);
1801 if (*sd_size_ret <= 0)
1802 {
1803 __seterrno ();
1804 return NULL;
1805 }
2a6fc028 1806 if (!MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret))
1fd5e000
CF
1807 {
1808 __seterrno ();
1809 return NULL;
1810 }
1fd5e000
CF
1811 debug_printf ("Created SD-Size: %d", *sd_size_ret);
1812
ab2dbccc 1813 return sd_ret;
1fd5e000
CF
1814}
1815
86fb0393
CV
1816void
1817set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa,
1818 void *sd_buf, DWORD sd_buf_size)
1819{
86fb0393 1820 psa->lpSecurityDescriptor = sd_buf;
5519d543 1821 InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR) sd_buf,
1ff9f4b9 1822 SECURITY_DESCRIPTOR_REVISION);
5519d543
CV
1823 psa->lpSecurityDescriptor = alloc_sd (geteuid32 (), getegid32 (), attribute,
1824 (PSECURITY_DESCRIPTOR) sd_buf,
86fb0393
CV
1825 &sd_buf_size);
1826}
1827
1fd5e000 1828static int
a8d7ae61 1829set_nt_attribute (const char *file, __uid32_t uid, __gid32_t gid,
2e8abfc1 1830 int attribute)
1fd5e000 1831{
ba946828 1832 if (!wincap.has_security ())
1fd5e000
CF
1833 return 0;
1834
1fd5e000
CF
1835 DWORD sd_size = 4096;
1836 char sd_buf[4096];
1837 PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf;
1838
1839 int ret;
d6581f44 1840 if ((ret = read_sd (file, psd, &sd_size)) <= 0)
1fd5e000 1841 {
d6581f44 1842 debug_printf ("read_sd %E");
2a9366ff 1843 return -1;
1fd5e000
CF
1844 }
1845
1846 sd_size = 4096;
2e8abfc1 1847 if (!(psd = alloc_sd (uid, gid, attribute, psd, &sd_size)))
1fd5e000
CF
1848 return -1;
1849
d6581f44 1850 return write_sd (file, psd, sd_size);
1fd5e000
CF
1851}
1852
1853int
1854set_file_attribute (int use_ntsec, const char *file,
5519d543 1855 __uid32_t uid, __gid32_t gid, int attribute)
1fd5e000 1856{
842c741f
CV
1857 int ret = 0;
1858
1859 if (use_ntsec && allow_ntsec)
2e8abfc1 1860 ret = set_nt_attribute (file, uid, gid, attribute);
842c741f
CV
1861 else if (allow_ntea && !NTWriteEA (file, ".UNIXATTR", (char *) &attribute,
1862 sizeof (attribute)))
1fd5e000 1863 {
842c741f
CV
1864 __seterrno ();
1865 ret = -1;
1fd5e000 1866 }
1fd5e000 1867 syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)",
5d4af61e
CV
1868 ret, file, uid, gid, attribute);
1869 return ret;
1fd5e000
CF
1870}
1871
1872int
1873set_file_attribute (int use_ntsec, const char *file, int attribute)
1874{
1875 return set_file_attribute (use_ntsec, file,
5519d543 1876 myself->uid, myself->gid, attribute);
1fd5e000 1877}
cf762b08
CV
1878
1879int
1880check_file_access (const char *fn, int flags)
1881{
1882 int ret = -1;
1883 char sd_buf[4096];
1884 DWORD sd_size = sizeof sd_buf;
1885 PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf;
1886 HANDLE hToken, hIToken;
1887 BOOL status;
1888 char pbuf[sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES)];
1889 DWORD desired = 0, granted, plength = sizeof pbuf;
1890 static GENERIC_MAPPING NO_COPY mapping = { FILE_GENERIC_READ,
1891 FILE_GENERIC_WRITE,
1892 FILE_GENERIC_EXECUTE,
1893 FILE_ALL_ACCESS };
1894 if (read_sd (fn, psd, &sd_size) <= 0)
1895 goto done;
1896
1897 if (cygheap->user.issetuid ())
70249d56 1898 hToken = cygheap->user.token ();
cf762b08
CV
1899 else if (!OpenProcessToken (hMainProc, TOKEN_DUPLICATE, &hToken))
1900 {
1901 __seterrno ();
1902 goto done;
1903 }
1904 if (!(status = DuplicateToken (hToken, SecurityIdentification, &hIToken)))
1905 __seterrno ();
70249d56 1906 if (!cygheap->user.issetuid ())
cf762b08
CV
1907 CloseHandle (hToken);
1908 if (!status)
1909 goto done;
1910
1911 if (flags & R_OK)
1912 desired |= FILE_READ_DATA;
1913 if (flags & W_OK)
1914 desired |= FILE_WRITE_DATA;
1915 if (flags & X_OK)
1916 desired |= FILE_EXECUTE;
1917 if (!AccessCheck (psd, hIToken, desired, &mapping,
1918 (PPRIVILEGE_SET) pbuf, &plength, &granted, &status))
1919 __seterrno ();
1920 else if (!status)
1921 set_errno (EACCES);
1922 else
1923 ret = 0;
1924 CloseHandle (hIToken);
1925 done:
1926 debug_printf ("flags %x, ret %d", flags, ret);
1927 return ret;
1928}
This page took 0.883935 seconds and 5 git commands to generate.