1 /* security.cc: NT security functions
3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
5 Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
6 Completely rewritten by Corinna Vinschen <corinna@vinschen.de>
8 This file is part of Cygwin.
10 This software is a copyrighted work licensed under the terms of the
11 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
20 #include <sys/types.h>
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. */
50 cygsidlist::alloc_sids (int n
)
53 return (cygsid
*) cmalloc (HEAP_STR
, n
* sizeof (cygsid
));
59 cygsidlist::free_sids ()
65 type
= cygsidlist_empty
;
69 cygwin_set_impersonation_token (const HANDLE hToken
)
71 debug_printf ("set_impersonation_token (%d)", hToken
);
72 cygheap
->user
.external_token
= hToken
;
77 extract_nt_dom_user (const struct passwd
*pw
, char *domain
, char *user
)
82 strlcpy (user
, pw
->pw_name
, UNLEN
+ 1);
83 debug_printf ("pw_gecos = %x (%s)", pw
->pw_gecos
, pw
->pw_gecos
);
85 if ((d
= strstr (pw
->pw_gecos
, "U-")) != NULL
&&
86 (d
== pw
->pw_gecos
|| d
[-1] == ','))
88 c
= strechr (d
+ 2, ',');
89 if ((u
= strechr (d
+ 2, '\\')) >= c
)
91 else if (u
- d
<= INTERNET_MAX_HOST_NAME_LENGTH
+ 2)
92 strlcpy (domain
, d
+ 2, u
- d
- 1);
93 if (c
- u
<= UNLEN
+ 1)
94 strlcpy (user
, u
+ 1, c
- u
);
100 DWORD ulen
= UNLEN
+ 1;
101 DWORD dlen
= INTERNET_MAX_HOST_NAME_LENGTH
+ 1;
103 if (psid
.getfrompw (pw
))
104 LookupAccountSid (NULL
, psid
, user
, &ulen
, domain
, &dlen
, &use
);
108 cygwin_logon_user (const struct passwd
*pw
, const char *password
)
110 if (!wincap
.has_security ())
113 return INVALID_HANDLE_VALUE
;
118 return INVALID_HANDLE_VALUE
;
121 char nt_domain
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
122 char nt_user
[UNLEN
+ 1];
125 extract_nt_dom_user (pw
, nt_domain
, nt_user
);
126 debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user
, nt_domain
, password
);
127 if (!LogonUserA (nt_user
, *nt_domain
? nt_domain
: NULL
, (char *) password
,
128 LOGON32_LOGON_INTERACTIVE
,
129 LOGON32_PROVIDER_DEFAULT
,
131 || !SetHandleInformation (hToken
,
133 HANDLE_FLAG_INHERIT
))
136 return INVALID_HANDLE_VALUE
;
138 debug_printf ("%d = logon_user(%s,...)", hToken
, pw
->pw_name
);
143 str2lsa (LSA_STRING
&tgt
, const char *srcstr
)
145 tgt
.Length
= strlen (srcstr
);
146 tgt
.MaximumLength
= tgt
.Length
+ 1;
147 tgt
.Buffer
= (PCHAR
) srcstr
;
151 str2buf2lsa (LSA_STRING
&tgt
, char *buf
, const char *srcstr
)
153 tgt
.Length
= strlen (srcstr
);
154 tgt
.MaximumLength
= tgt
.Length
+ 1;
155 tgt
.Buffer
= (PCHAR
) buf
;
156 memcpy (buf
, srcstr
, tgt
.MaximumLength
);
160 str2buf2uni (UNICODE_STRING
&tgt
, WCHAR
*buf
, const char *srcstr
)
162 tgt
.Length
= strlen (srcstr
) * sizeof (WCHAR
);
163 tgt
.MaximumLength
= tgt
.Length
+ sizeof (WCHAR
);
164 tgt
.Buffer
= (PWCHAR
) buf
;
165 sys_mbstowcs (buf
, srcstr
, tgt
.MaximumLength
);
170 lsa2wchar (WCHAR
*tgt
, LSA_UNICODE_STRING
&src
, int size
)
172 size
= (size
- 1) * sizeof (WCHAR
);
173 if (src
.Length
< size
)
175 memcpy (tgt
, src
.Buffer
, size
);
182 lsa2str (char *tgt
, LSA_UNICODE_STRING
&src
, int size
)
184 if (src
.Length
/ 2 < size
)
185 size
= src
.Length
/ 2;
186 sys_wcstombs (tgt
, src
.Buffer
, size
);
193 LSA_OBJECT_ATTRIBUTES oa
= { 0, 0, 0, 0, 0, 0 };
194 LSA_HANDLE lsa
= INVALID_HANDLE_VALUE
;
196 NTSTATUS ret
= LsaOpenPolicy (NULL
, &oa
, POLICY_EXECUTE
, &lsa
);
197 if (ret
!= STATUS_SUCCESS
)
198 __seterrno_from_win_error (LsaNtStatusToWinError (ret
));
203 close_local_policy (LSA_HANDLE
&lsa
)
205 if (lsa
!= INVALID_HANDLE_VALUE
)
207 lsa
= INVALID_HANDLE_VALUE
;
212 get_lsa_srv_inf (LSA_HANDLE lsa
, char *logonserver
, char *domain
)
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
;
222 if ((ret
= LsaQueryInformationPolicy (lsa
, PolicyAccountDomainInformation
,
223 (PVOID
*) &adi
)) != STATUS_SUCCESS
)
225 __seterrno_from_win_error (LsaNtStatusToWinError (ret
));
228 lsa2wchar (account
, adi
->DomainName
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
230 if ((ret
= LsaQueryInformationPolicy (lsa
, PolicyPrimaryDomainInformation
,
231 (PVOID
*) &pdi
)) != STATUS_SUCCESS
)
233 __seterrno_from_win_error (LsaNtStatusToWinError (ret
));
236 lsa2wchar (primary
, pdi
->Name
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
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. */
243 NetGetDCName (NULL
, primary
, (LPBYTE
*) &buf
)) == STATUS_SUCCESS
)
245 sys_wcstombs (name
, buf
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
246 strcpy (logonserver
, name
);
248 sys_wcstombs (domain
, primary
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
252 sys_wcstombs (name
, account
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
253 strcpy (logonserver
, "\\\\");
254 strcat (logonserver
, name
);
256 sys_wcstombs (domain
, account
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
258 if (ret
== STATUS_SUCCESS
)
259 NetApiBufferFree (buf
);
265 get_logon_server (const char *domain
, char *server
, WCHAR
*wserver
)
267 WCHAR wdomain
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
270 DWORD size
= INTERNET_MAX_HOST_NAME_LENGTH
+ 1;
272 /* Empty domain is interpreted as local system */
273 if ((GetComputerName (server
+ 2, &size
)) &&
274 (strcasematch (domain
, server
+ 2) || !domain
[0]))
276 server
[0] = server
[1] = '\\';
278 sys_mbstowcs (wserver
, server
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
282 /* Try to get the primary domain controller for the domain */
283 sys_mbstowcs (wdomain
, domain
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
284 if ((ret
= NetGetDCName (NULL
, wdomain
, (LPBYTE
*) &buf
)) == STATUS_SUCCESS
)
286 sys_wcstombs (server
, buf
, INTERNET_MAX_HOST_NAME_LENGTH
+ 1);
288 for (WCHAR
*ptr1
= buf
; (*wserver
++ = *ptr1
++);)
290 NetApiBufferFree (buf
);
293 __seterrno_from_win_error (ret
);
298 get_user_groups (WCHAR
*wlogonserver
, cygsidlist
&grp_list
, char *user
,
301 char dgroup
[INTERNET_MAX_HOST_NAME_LENGTH
+ GNLEN
+ 2];
302 WCHAR wuser
[UNLEN
+ 1];
303 sys_mbstowcs (wuser
, user
, UNLEN
+ 1);
304 LPGROUP_USERS_INFO_0 buf
;
308 /* Look only on logonserver */
309 ret
= NetUserGetGroups (wlogonserver
, wuser
, 0, (LPBYTE
*) &buf
,
310 MAX_PREFERRED_LENGTH
, &cnt
, &tot
);
313 __seterrno_from_win_error (ret
);
314 /* It's no error when the user name can't be found. */
315 return ret
== NERR_UserNotFound
;
318 len
= strlen (domain
);
319 strcpy (dgroup
, domain
);
320 dgroup
[len
++] = '\\';
322 for (DWORD i
= 0; i
< cnt
; ++i
)
325 DWORD glen
= MAX_SID_LEN
;
326 char domain
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
327 DWORD dlen
= sizeof (domain
);
328 SID_NAME_USE use
= SidTypeInvalid
;
330 sys_wcstombs (dgroup
+ len
, buf
[i
].grui0_name
, GNLEN
+ 1);
331 if (!LookupAccountName (NULL
, dgroup
, gsid
, &glen
, domain
, &dlen
, &use
))
332 debug_printf ("LookupAccountName(%s): %E", dgroup
);
333 else if (legal_sid_type (use
))
336 debug_printf ("Global group %s invalid. Domain: %s Use: %d",
337 dgroup
, domain
, use
);
340 NetApiBufferFree (buf
);
345 is_group_member (WCHAR
*wgroup
, PSID pusersid
, cygsidlist
&grp_list
)
347 LPLOCALGROUP_MEMBERS_INFO_0 buf
;
352 /* Members can be users or global groups */
353 ret
= NetLocalGroupGetMembers (NULL
, wgroup
, 0, (LPBYTE
*) &buf
,
354 MAX_PREFERRED_LENGTH
, &cnt
, &tot
, NULL
);
358 for (DWORD bidx
= 0; !retval
&& bidx
< cnt
; ++bidx
)
359 if (EqualSid (pusersid
, buf
[bidx
].lgrmi0_sid
))
362 for (int glidx
= 0; !retval
&& glidx
< grp_list
.count
; ++glidx
)
363 if (EqualSid (grp_list
.sids
[glidx
], buf
[bidx
].lgrmi0_sid
))
366 NetApiBufferFree (buf
);
371 get_user_local_groups (cygsidlist
&grp_list
, PSID pusersid
)
373 LPLOCALGROUP_INFO_0 buf
;
377 ret
= NetLocalGroupEnum (NULL
, 0, (LPBYTE
*) &buf
,
378 MAX_PREFERRED_LENGTH
, &cnt
, &tot
, NULL
);
381 __seterrno_from_win_error (ret
);
385 char bgroup
[INTERNET_MAX_HOST_NAME_LENGTH
+ GNLEN
+ 2];
386 char lgroup
[INTERNET_MAX_HOST_NAME_LENGTH
+ GNLEN
+ 2];
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)))
397 bgroup
[blen
++] = lgroup
[llen
++] = '\\';
399 for (DWORD i
= 0; i
< cnt
; ++i
)
400 if (is_group_member (buf
[i
].lgrpi0_name
, pusersid
, grp_list
))
403 DWORD glen
= MAX_SID_LEN
;
404 char domain
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
405 DWORD dlen
= sizeof (domain
);
407 use
= SidTypeInvalid
;
408 sys_wcstombs (bgroup
+ blen
, buf
[i
].lgrpi0_name
, GNLEN
+ 1);
409 if (!LookupAccountName (NULL
, bgroup
, gsid
, &glen
, domain
, &dlen
, &use
))
411 if (GetLastError () != ERROR_NONE_MAPPED
)
412 debug_printf ("LookupAccountName(%s): %E", bgroup
);
413 strcpy (lgroup
+ llen
, bgroup
+ blen
);
414 if (!LookupAccountName (NULL
, lgroup
, gsid
, &glen
,
415 domain
, &dlen
, &use
))
416 debug_printf ("LookupAccountName(%s): %E", lgroup
);
418 if (!legal_sid_type (use
))
419 debug_printf ("Rejecting local %s. use: %d", bgroup
+ blen
, use
);
420 else if (!grp_list
.contains (gsid
))
423 NetApiBufferFree (buf
);
428 sid_in_token_groups (PTOKEN_GROUPS grps
, cygsid
&sid
)
432 for (DWORD i
= 0; i
< grps
->GroupCount
; ++i
)
433 if (sid
== grps
->Groups
[i
].Sid
)
440 get_user_primary_group (WCHAR
*wlogonserver
, const char *user
,
441 PSID pusersid
, cygsid
&pgrpsid
)
444 WCHAR wuser
[UNLEN
+ 1];
449 if (well_known_system_sid
== pusersid
)
451 pgrpsid
= well_known_system_sid
;
455 sys_mbstowcs (wuser
, user
, UNLEN
+ 1);
456 ret
= NetUserGetInfo (wlogonserver
, wuser
, 3, (LPBYTE
*) &buf
);
459 __seterrno_from_win_error (ret
);
464 if (IsValidSid (pgrpsid
)
465 && (count
= *GetSidSubAuthorityCount (pgrpsid
)) > 1)
467 *GetSidSubAuthority (pgrpsid
, count
- 1) = buf
->usri3_primary_group_id
;
470 NetApiBufferFree (buf
);
476 get_unix_group_sidlist (struct passwd
*pw
, cygsidlist
&grp_list
)
478 struct __group32
*gr
;
481 for (int gidx
= 0; (gr
= internal_getgrent (gidx
)); ++gidx
)
483 if (gr
->gr_gid
== (__gid32_t
) pw
->pw_gid
)
486 for (int gi
= 0; gr
->gr_mem
[gi
]; ++gi
)
487 if (strcasematch (pw
->pw_name
, gr
->gr_mem
[gi
]))
491 if (gsid
.getfromgr (gr
) && !grp_list
.contains (gsid
))
498 get_token_group_sidlist (cygsidlist
&grp_list
, PTOKEN_GROUPS my_grps
,
499 LUID auth_luid
, int &auth_pos
)
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
;
519 grp_list
+= well_known_local_sid
;
520 grp_list
+= well_known_interactive_sid
;
522 if (auth_luid
.QuadPart
!= 999) /* != SYSTEM_LUID */
525 __small_sprintf (buf
, "S-1-5-5-%u-%u", auth_luid
.HighPart
,
528 auth_pos
= grp_list
.count
- 1;
533 get_initgroups_sidlist (cygsidlist
&grp_list
,
534 PSID usersid
, PSID pgrpsid
, struct passwd
*pw
,
535 PTOKEN_GROUPS my_grps
, LUID auth_luid
, int &auth_pos
,
538 grp_list
+= well_known_world_sid
;
539 grp_list
+= well_known_authenticated_users_sid
;
540 if (well_known_system_sid
== usersid
)
543 grp_list
+= well_known_admins_sid
;
544 get_unix_group_sidlist (pw
, grp_list
);
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];
553 get_token_group_sidlist (grp_list
, my_grps
, auth_luid
, auth_pos
);
554 extract_nt_dom_user (pw
, domain
, user
);
555 if (get_logon_server (domain
, server
, wserver
))
556 get_user_groups (wserver
, grp_list
, user
, domain
);
557 get_unix_group_sidlist (pw
, grp_list
);
558 if (!get_user_local_groups (grp_list
, usersid
))
561 /* special_pgrp true if pgrpsid is not in normal groups */
562 if ((special_pgrp
= !grp_list
.contains (pgrpsid
)))
568 get_setgroups_sidlist (cygsidlist
&tmp_list
, PTOKEN_GROUPS my_grps
,
569 user_groups
&groups
, LUID auth_luid
, int &auth_pos
)
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
))
581 static const char *sys_privs
[] = {
583 SE_ASSIGNPRIMARYTOKEN_NAME
,
584 SE_CREATE_TOKEN_NAME
,
585 SE_CHANGE_NOTIFY_NAME
,
591 SE_REMOTE_SHUTDOWN_NAME
,
592 SE_TAKE_OWNERSHIP_NAME
,
594 SE_SYSTEM_ENVIRONMENT_NAME
,
595 SE_SYSTEM_PROFILE_NAME
,
596 SE_PROF_SINGLE_PROCESS_NAME
,
597 SE_INC_BASE_PRIORITY_NAME
,
599 SE_CREATE_PAGEFILE_NAME
,
600 SE_INCREASE_QUOTA_NAME
603 #define SYSTEM_PERMISSION_COUNT (sizeof sys_privs / sizeof (const char *))
606 get_system_priv_list (cygsidlist
&grp_list
)
609 PTOKEN_PRIVILEGES privs
= (PTOKEN_PRIVILEGES
)
610 malloc (sizeof (ULONG
) + 20 * sizeof (LUID_AND_ATTRIBUTES
));
613 debug_printf ("malloc (system_privs) failed.");
616 privs
->PrivilegeCount
= 0;
618 for (DWORD i
= 0; i
< SYSTEM_PERMISSION_COUNT
; ++i
)
619 if (LookupPrivilegeValue (NULL
, sys_privs
[i
], &priv
))
621 privs
->Privileges
[privs
->PrivilegeCount
].Luid
= priv
;
622 privs
->Privileges
[privs
->PrivilegeCount
].Attributes
=
623 SE_PRIVILEGE_ENABLED
| SE_PRIVILEGE_ENABLED_BY_DEFAULT
;
624 ++privs
->PrivilegeCount
;
630 get_priv_list (LSA_HANDLE lsa
, cygsid
&usersid
, cygsidlist
&grp_list
)
632 PLSA_UNICODE_STRING privstrs
;
634 PTOKEN_PRIVILEGES privs
= NULL
;
636 char buf
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
638 if (usersid
== well_known_system_sid
)
639 return get_system_priv_list (grp_list
);
641 for (int grp
= -1; grp
< grp_list
.count
; ++grp
)
645 if ((ret
= LsaEnumerateAccountRights (lsa
, usersid
, &privstrs
,
646 &cnt
)) != STATUS_SUCCESS
)
649 else if ((ret
= LsaEnumerateAccountRights (lsa
, grp_list
.sids
[grp
],
653 for (ULONG i
= 0; i
< cnt
; ++i
)
656 PTOKEN_PRIVILEGES tmp
;
659 lsa2str (buf
, privstrs
[i
], sizeof (buf
) - 1);
660 if (!LookupPrivilegeValue (NULL
, buf
, &priv
))
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
;
667 tmp_count
= privs
? privs
->PrivilegeCount
: 0;
668 tmp
= (PTOKEN_PRIVILEGES
)
669 realloc (privs
, sizeof (ULONG
) +
670 (tmp_count
+ 1) * sizeof (LUID_AND_ATTRIBUTES
));
675 LsaFreeMemory (privstrs
);
676 debug_printf ("realloc (privs) failed.");
679 tmp
->PrivilegeCount
= tmp_count
;
681 privs
->Privileges
[privs
->PrivilegeCount
].Luid
= priv
;
682 privs
->Privileges
[privs
->PrivilegeCount
].Attributes
=
683 SE_PRIVILEGE_ENABLED
| SE_PRIVILEGE_ENABLED_BY_DEFAULT
;
684 ++privs
->PrivilegeCount
;
689 LsaFreeMemory (privstrs
);
695 - the requested usersid matches the TokenUser and
696 - if setgroups has been called:
697 the token groups that are listed in /etc/group match the union of
698 the requested primary and supplementary groups in gsids.
699 - else the (unknown) implicitly requested supplementary groups and those
700 in the token are the groups associated with the usersid. We assume
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. */
708 verify_token (HANDLE token
, cygsid
&usersid
, user_groups
&groups
, BOOL
*pintern
)
716 if (!GetTokenInformation (token
, TokenSource
,
717 &ts
, sizeof ts
, &size
))
718 debug_printf ("GetTokenInformation(): %E");
720 *pintern
= intern
= !memcmp (ts
.SourceName
, "Cygwin.1", 8);
723 cygsid tok_usersid
= NO_SID
;
724 if (!GetTokenInformation (token
, TokenUser
,
725 &tok_usersid
, sizeof tok_usersid
, &size
))
726 debug_printf ("GetTokenInformation(): %E");
727 if (usersid
!= tok_usersid
)
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 ())
734 char sd_buf
[MAX_SID_LEN
+ sizeof (SECURITY_DESCRIPTOR
)];
735 cygpsid
gsid (NO_SID
);
736 if (!GetKernelObjectSecurity (token
, GROUP_SECURITY_INFORMATION
,
737 (PSECURITY_DESCRIPTOR
) sd_buf
,
738 sizeof sd_buf
, &size
))
739 debug_printf ("GetKernelObjectSecurity(): %E");
740 else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR
) sd_buf
,
741 (PSID
*) &gsid
, (BOOL
*) &size
))
742 debug_printf ("GetSecurityDescriptorGroup(): %E");
743 if (well_known_null_sid
!= gsid
)
744 return gsid
== groups
.pgsid
;
747 PTOKEN_GROUPS my_grps
;
748 bool saw_buf
[NGROUPS_MAX
] = {};
749 bool *saw
= saw_buf
, sawpg
= false, ret
= false;
751 if (!GetTokenInformation (token
, TokenGroups
, NULL
, 0, &size
) &&
752 GetLastError () != ERROR_INSUFFICIENT_BUFFER
)
753 debug_printf ("GetTokenInformation(token, TokenGroups): %E");
754 else if (!(my_grps
= (PTOKEN_GROUPS
) alloca (size
)))
755 debug_printf ("alloca (my_grps) failed.");
756 else if (!GetTokenInformation (token
, TokenGroups
, my_grps
, size
, &size
))
757 debug_printf ("GetTokenInformation(my_token, TokenGroups): %E");
758 else if (!groups
.issetgroups ()) /* setgroups was never called */
759 ret
= sid_in_token_groups (my_grps
, groups
.pgsid
)
760 || groups
.pgsid
== usersid
;
761 else /* setgroups was called */
763 struct __group32
*gr
;
765 if (groups
.sgsids
.count
> (int) (sizeof (saw_buf
) / sizeof (*saw_buf
))
766 && !(saw
= (bool *) calloc (groups
.sgsids
.count
, sizeof (bool))))
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
))
773 int pos
= groups
.sgsids
.position (gsid
);
776 else if (groups
.pgsid
== gsid
)
778 else if (gsid
!= well_known_world_sid
782 for (int gidx
= 0; gidx
< groups
.sgsids
.count
; gidx
++)
786 || groups
.sgsids
.contains (groups
.pgsid
)
787 || groups
.pgsid
== usersid
;
796 create_token (cygsid
&usersid
, user_groups
&new_groups
, struct passwd
*pw
)
799 LSA_HANDLE lsa
= INVALID_HANDLE_VALUE
;
802 cygsidlist
tmp_gsids (cygsidlist_auto
, 12);
804 SECURITY_QUALITY_OF_SERVICE sqos
=
805 { sizeof sqos
, SecurityImpersonation
, SECURITY_STATIC_TRACKING
, FALSE
};
806 OBJECT_ATTRIBUTES oa
= { sizeof oa
, 0, 0, 0, 0, &sqos
};
807 PSECURITY_ATTRIBUTES psa
;
808 BOOL special_pgrp
= FALSE
;
810 LUID auth_luid
= SYSTEM_LUID
;
811 LARGE_INTEGER exp
= { QuadPart
:0x7fffffffffffffffLL
};
814 PTOKEN_GROUPS new_tok_gsids
= NULL
;
815 PTOKEN_PRIVILEGES privs
= NULL
;
817 TOKEN_PRIMARY_GROUP pgrp
;
818 char acl_buf
[MAX_DACL_LEN (5)];
819 TOKEN_DEFAULT_DACL dacl
;
821 TOKEN_STATISTICS stats
;
822 memcpy (source
.SourceName
, "Cygwin.1", 8);
823 source
.SourceIdentifier
.HighPart
= 0;
824 source
.SourceIdentifier
.LowPart
= 0x0101;
826 HANDLE token
= INVALID_HANDLE_VALUE
;
827 HANDLE primary_token
= INVALID_HANDLE_VALUE
;
829 HANDLE my_token
= INVALID_HANDLE_VALUE
;
830 PTOKEN_GROUPS my_tok_gsids
= NULL
;
833 /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
834 if ((old_priv_state
= set_process_privilege (SE_CREATE_TOKEN_NAME
)) < 0)
837 /* Open policy object. */
838 if ((lsa
= open_local_policy ()) == INVALID_HANDLE_VALUE
)
841 /* User, owner, primary group. */
842 user
.User
.Sid
= usersid
;
843 user
.User
.Attributes
= 0;
844 owner
.Owner
= usersid
;
846 /* Retrieve authentication id and group list from own process. */
847 if (!OpenProcessToken (hMainProc
, TOKEN_QUERY
, &my_token
))
848 debug_printf ("OpenProcessToken(my_token): %E");
851 /* Switching user context to SYSTEM doesn't inherit the authentication
852 id of the user account running current process. */
853 if (usersid
!= well_known_system_sid
)
854 if (!GetTokenInformation (my_token
, TokenStatistics
,
855 &stats
, sizeof stats
, &size
))
857 ("GetTokenInformation(my_token, TokenStatistics): %E");
859 auth_luid
= stats
.AuthenticationId
;
861 /* Retrieving current processes group list to be able to inherit
862 some important well known group sids. */
863 if (!GetTokenInformation (my_token
, TokenGroups
, NULL
, 0, &size
) &&
864 GetLastError () != ERROR_INSUFFICIENT_BUFFER
)
865 debug_printf ("GetTokenInformation(my_token, TokenGroups): %E");
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
,
871 debug_printf ("GetTokenInformation(my_token, TokenGroups): %E");
875 CloseHandle (my_token
);
878 /* Create list of groups, the user is member in. */
880 if (new_groups
.issetgroups ())
881 get_setgroups_sidlist (tmp_gsids
, my_tok_gsids
, new_groups
, auth_luid
,
883 else if (!get_initgroups_sidlist (tmp_gsids
, usersid
, new_groups
.pgsid
, pw
,
884 my_tok_gsids
, auth_luid
, auth_pos
,
889 pgrp
.PrimaryGroup
= new_groups
.pgsid
;
891 /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
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
)
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
;
902 new_tok_gsids
->Groups
[auth_pos
].Attributes
|= SE_GROUP_LOGON_ID
;
904 /* Retrieve list of privileges of that user. */
905 if (!(privs
= get_priv_list (lsa
, usersid
, tmp_gsids
)))
908 /* Create default dacl. */
909 if (!sec_acl ((PACL
) acl_buf
, false, false,
910 tmp_gsids
.contains (well_known_admins_sid
) ?
911 well_known_admins_sid
: usersid
))
913 dacl
.DefaultDacl
= (PACL
) acl_buf
;
915 /* Let's be heroic... */
916 ret
= NtCreateToken (&token
, TOKEN_ALL_ACCESS
, &oa
, TokenImpersonation
,
917 &auth_luid
, &exp
, &user
, new_tok_gsids
, privs
, &owner
,
918 &pgrp
, &dacl
, &source
);
920 __seterrno_from_win_error (RtlNtStatusToDosError (ret
));
921 else if (GetLastError () == ERROR_PROC_NOT_FOUND
)
924 debug_printf ("Loading NtCreateToken failed.");
928 /* Set security descriptor and primary group */
929 psa
= sec_user (sa_buf
, usersid
);
930 if (psa
->lpSecurityDescriptor
&&
931 !SetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR
)
932 psa
->lpSecurityDescriptor
,
933 special_pgrp
? new_groups
.pgsid
934 : well_known_null_sid
,
936 debug_printf ("SetSecurityDescriptorGroup %E");
937 /* Convert to primary token. */
938 if (!DuplicateTokenEx (token
, MAXIMUM_ALLOWED
, psa
, SecurityImpersonation
,
939 TokenPrimary
, &primary_token
))
942 debug_printf ("DuplicateTokenEx %E");
947 if (old_priv_state
>= 0)
948 set_process_privilege (SE_CREATE_TOKEN_NAME
, old_priv_state
);
949 if (token
!= INVALID_HANDLE_VALUE
)
955 close_local_policy (lsa
);
957 debug_printf ("%d = create_token ()", primary_token
);
958 return primary_token
;
961 int subauth_id
= 255;
964 subauth (struct passwd
*pw
)
968 LSA_OPERATIONAL_MODE sec_mode
;
970 ULONG package_id
, size
;
976 MSV1_0_LM20_LOGON auth
;
977 WCHAR dombuf
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
978 WCHAR usrbuf
[UNLEN
+ 1];
984 PMSV1_0_LM20_LOGON_PROFILE profile
;
987 char nt_domain
[INTERNET_MAX_HOST_NAME_LENGTH
+ 1];
988 char nt_user
[UNLEN
+ 1];
989 SECURITY_ATTRIBUTES sa
= { sizeof sa
, NULL
, TRUE
};
990 HANDLE user_token
= INVALID_HANDLE_VALUE
;
991 HANDLE primary_token
= INVALID_HANDLE_VALUE
;
994 if ((old_tcb_state
= set_process_privilege (SE_TCB_NAME
)) < 0)
995 return INVALID_HANDLE_VALUE
;
997 /* Register as logon process. */
998 str2lsa (name
, "Cygwin");
1000 ret
= LsaRegisterLogonProcess (&name
, &lsa_hdl
, &sec_mode
);
1001 if (ret
!= STATUS_SUCCESS
)
1003 debug_printf ("LsaRegisterLogonProcess: %d", ret
);
1004 __seterrno_from_win_error (LsaNtStatusToWinError (ret
));
1007 else if (GetLastError () == ERROR_PROC_NOT_FOUND
)
1009 debug_printf ("Couldn't load Secur32.dll");
1012 /* Get handle to MSV1_0 package. */
1013 str2lsa (name
, MSV1_0_PACKAGE_NAME
);
1014 ret
= LsaLookupAuthenticationPackage (lsa_hdl
, &name
, &package_id
);
1015 if (ret
!= STATUS_SUCCESS
)
1017 debug_printf ("LsaLookupAuthenticationPackage: %d", ret
);
1018 __seterrno_from_win_error (LsaNtStatusToWinError (ret
));
1019 LsaDeregisterLogonProcess (lsa_hdl
);
1022 /* Create origin. */
1023 str2buf2lsa (origin
.str
, origin
.buf
, "Cygwin");
1024 /* Create token source. */
1025 memcpy (ts
.SourceName
, "Cygwin.1", 8);
1026 ts
.SourceIdentifier
.HighPart
= 0;
1027 ts
.SourceIdentifier
.LowPart
= 0x0100;
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
;
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
, "");
1037 str2buf2lsa (subbuf
.auth
.CaseInsensitiveChallengeResponse
,subbuf
.authinf2
,"");
1038 subbuf
.auth
.ParameterControl
= 0 | (subauth_id
<< 24);
1039 /* Try to logon... */
1040 ret
= LsaLogonUser (lsa_hdl
, (PLSA_STRING
) &origin
, Network
,
1041 package_id
, &subbuf
, sizeof subbuf
,
1042 NULL
, &ts
, (PVOID
*) &profile
, &size
,
1043 &luid
, &user_token
, "a
, &ret2
);
1044 if (ret
!= STATUS_SUCCESS
)
1046 debug_printf ("LsaLogonUser: %d", ret
);
1047 __seterrno_from_win_error (LsaNtStatusToWinError (ret
));
1048 LsaDeregisterLogonProcess (lsa_hdl
);
1051 LsaFreeReturnBuffer (profile
);
1052 /* Convert to primary token. */
1053 if (!DuplicateTokenEx (user_token
, TOKEN_ALL_ACCESS
, &sa
,
1054 SecurityImpersonation
, TokenPrimary
, &primary_token
))
1058 set_process_privilege (SE_TCB_NAME
, old_tcb_state
);
1059 if (user_token
!= INVALID_HANDLE_VALUE
)
1060 CloseHandle (user_token
);
1061 return primary_token
;
1064 /* read_sd reads a security descriptor from a file.
1065 In case of error, -1 is returned and errno is set.
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.
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.
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
1081 read_sd (const char *file
, PSECURITY_DESCRIPTOR sd_buf
, LPDWORD sd_size
)
1083 /* Check parameters */
1090 debug_printf ("file = %s", file
);
1093 const char *pfile
= file
;
1094 char fbuf
[PATH_MAX
];
1095 if (current_codepage
== oem_cp
)
1097 DWORD fname_len
= min (sizeof (fbuf
) - 1, strlen (file
));
1098 bzero (fbuf
, sizeof (fbuf
));
1099 OemToCharBuff (file
, fbuf
, fname_len
);
1103 if (!GetFileSecurity (pfile
,
1104 OWNER_SECURITY_INFORMATION
1105 | GROUP_SECURITY_INFORMATION
1106 | DACL_SECURITY_INFORMATION
,
1107 sd_buf
, *sd_size
, &len
))
1112 debug_printf ("file = %s: len=%d", file
, len
);
1122 write_sd (const char *file
, PSECURITY_DESCRIPTOR sd_buf
, DWORD sd_size
)
1124 /* Check parameters */
1125 if (!sd_buf
|| !sd_size
)
1134 if (!GetSecurityDescriptorOwner (sd_buf
, (PSID
*) &owner
, &dummy
))
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 */
1143 if (!saved_res
|| cygheap
->user
.issetuid ())
1145 res
= 2 + set_process_privilege (SE_RESTORE_NAME
, true,
1146 cygheap
->user
.issetuid ());
1147 if (!cygheap
->user
.issetuid ())
1152 if (res
== 1 && owner
!= cygheap
->user
.sid ())
1156 fh
= CreateFile (file
,
1157 WRITE_OWNER
| WRITE_DAC
,
1158 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1161 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
,
1164 if (fh
== INVALID_HANDLE_VALUE
)
1170 LPVOID context
= NULL
;
1171 DWORD bytes_written
= 0;
1172 WIN32_STREAM_ID header
;
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;
1179 header
.Size
.LowPart
= sd_size
;
1180 header
.dwStreamNameSize
= 0;
1181 if (!BackupWrite (fh
, (LPBYTE
) &header
,
1182 3 * sizeof (DWORD
) + sizeof (LARGE_INTEGER
),
1183 &bytes_written
, FALSE
, TRUE
, &context
))
1190 /* write new security descriptor */
1191 if (!BackupWrite (fh
, (LPBYTE
) sd_buf
,
1192 header
.Size
.LowPart
+ header
.dwStreamNameSize
,
1193 &bytes_written
, FALSE
, TRUE
, &context
))
1195 /* Samba returns ERROR_NOT_SUPPORTED.
1196 FAT returns ERROR_INVALID_SECURITY_DESCR.
1197 This shouldn't return as error, but better be ignored. */
1198 DWORD ret
= GetLastError ();
1199 if (ret
!= ERROR_NOT_SUPPORTED
&& ret
!= ERROR_INVALID_SECURITY_DESCR
)
1202 BackupWrite (fh
, NULL
, 0, &bytes_written
, TRUE
, TRUE
, &context
);
1208 /* terminate the restore process */
1209 BackupWrite (fh
, NULL
, 0, &bytes_written
, TRUE
, TRUE
, &context
);
1215 get_attribute_from_acl (mode_t
*attribute
, PACL acl
, PSID owner_sid
,
1216 PSID group_sid
, BOOL grp_member
)
1218 ACCESS_ALLOWED_ACE
*ace
;
1223 for (DWORD i
= 0; i
< acl
->AceCount
; ++i
)
1225 if (!GetAce (acl
, i
, (PVOID
*) &ace
))
1227 if (ace
->Header
.AceFlags
& INHERIT_ONLY
)
1229 switch (ace
->Header
.AceType
)
1231 case ACCESS_ALLOWED_ACE_TYPE
:
1235 case ACCESS_DENIED_ACE_TYPE
:
1243 cygpsid
ace_sid ((PSID
) &ace
->SidStart
);
1244 if (ace_sid
== well_known_world_sid
)
1246 if (ace
->Mask
& FILE_READ_DATA
)
1247 *flags
|= ((!(*anti
& S_IROTH
)) ? S_IROTH
: 0)
1248 | ((!(*anti
& S_IRGRP
)) ? S_IRGRP
: 0)
1249 | ((!(*anti
& S_IRUSR
)) ? S_IRUSR
: 0);
1250 if (ace
->Mask
& FILE_WRITE_DATA
)
1251 *flags
|= ((!(*anti
& S_IWOTH
)) ? S_IWOTH
: 0)
1252 | ((!(*anti
& S_IWGRP
)) ? S_IWGRP
: 0)
1253 | ((!(*anti
& S_IWUSR
)) ? S_IWUSR
: 0);
1254 if (ace
->Mask
& FILE_EXECUTE
)
1255 *flags
|= ((!(*anti
& S_IXOTH
)) ? S_IXOTH
: 0)
1256 | ((!(*anti
& S_IXGRP
)) ? S_IXGRP
: 0)
1257 | ((!(*anti
& S_IXUSR
)) ? S_IXUSR
: 0);
1258 if ((S_ISDIR (*attribute
)) &&
1259 (ace
->Mask
& (FILE_WRITE_DATA
| FILE_EXECUTE
| FILE_DELETE_CHILD
))
1260 == (FILE_WRITE_DATA
| FILE_EXECUTE
))
1263 else if (ace_sid
== well_known_null_sid
)
1265 /* Read SUID, SGID and VTX bits from NULL ACE. */
1266 if (ace
->Mask
& FILE_READ_DATA
)
1268 if (ace
->Mask
& FILE_WRITE_DATA
)
1270 if (ace
->Mask
& FILE_APPEND_DATA
)
1273 else if (ace_sid
== owner_sid
)
1275 if (ace
->Mask
& FILE_READ_DATA
)
1276 *flags
|= ((!(*anti
& S_IRUSR
)) ? S_IRUSR
: 0);
1277 if (ace
->Mask
& FILE_WRITE_DATA
)
1278 *flags
|= ((!(*anti
& S_IWUSR
)) ? S_IWUSR
: 0);
1279 if (ace
->Mask
& FILE_EXECUTE
)
1280 *flags
|= ((!(*anti
& S_IXUSR
)) ? S_IXUSR
: 0);
1282 else if (ace_sid
== group_sid
)
1284 if (ace
->Mask
& FILE_READ_DATA
)
1285 *flags
|= ((!(*anti
& S_IRGRP
)) ? S_IRGRP
: 0)
1286 | ((grp_member
&& !(*anti
& S_IRUSR
)) ? S_IRUSR
: 0);
1287 if (ace
->Mask
& FILE_WRITE_DATA
)
1288 *flags
|= ((!(*anti
& S_IWGRP
)) ? S_IWGRP
: 0)
1289 | ((grp_member
&& !(*anti
& S_IWUSR
)) ? S_IWUSR
: 0);
1290 if (ace
->Mask
& FILE_EXECUTE
)
1291 *flags
|= ((!(*anti
& S_IXGRP
)) ? S_IXGRP
: 0)
1292 | ((grp_member
&& !(*anti
& S_IXUSR
)) ? S_IXUSR
: 0);
1295 *attribute
&= ~(S_IRWXU
| S_IRWXG
| S_IRWXO
| S_ISVTX
| S_ISGID
| S_ISUID
);
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
)
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));
1305 *attribute
|= allow
;
1310 get_info_from_sd (PSECURITY_DESCRIPTOR psd
, mode_t
*attribute
,
1311 __uid32_t
*uidret
, __gid32_t
*gidret
)
1315 /* If reading the security descriptor failed, treat the object
1318 *attribute
&= ~(S_IRWXU
| S_IRWXG
| S_IRWXO
);
1320 *uidret
= ILLEGAL_UID
;
1322 *gidret
= ILLEGAL_GID
;
1330 if (!GetSecurityDescriptorOwner (psd
, (PSID
*) &owner_sid
, &dummy
))
1331 debug_printf ("GetSecurityDescriptorOwner %E");
1332 if (!GetSecurityDescriptorGroup (psd
, (PSID
*) &group_sid
, &dummy
))
1333 debug_printf ("GetSecurityDescriptorGroup %E");
1337 BOOL grp_member
= get_sids_info (owner_sid
, group_sid
, &uid
, &gid
);
1345 syscall_printf ("uid %d, gid %d", uid
, gid
);
1352 if (!GetSecurityDescriptorDacl (psd
, &acl_exists
, &acl
, &dummy
))
1355 debug_printf ("GetSecurityDescriptorDacl %E");
1356 *attribute
&= ~(S_IRWXU
| S_IRWXG
| S_IRWXO
);
1358 else if (!acl_exists
|| !acl
)
1359 *attribute
|= S_IRWXU
| S_IRWXG
| S_IRWXO
;
1361 get_attribute_from_acl (attribute
, acl
, owner_sid
, group_sid
, grp_member
);
1363 syscall_printf ("%sACL = %x, uid %d, gid %d",
1364 (!acl_exists
|| !acl
)?"NO ":"", *attribute
, uid
, gid
);
1369 get_nt_attribute (const char *file
, mode_t
*attribute
,
1370 __uid32_t
*uidret
, __gid32_t
*gidret
)
1372 /* Yeah, sounds too much, but I've seen SDs of 2100 bytes! */
1373 DWORD sd_size
= 4096;
1375 PSECURITY_DESCRIPTOR psd
= (PSECURITY_DESCRIPTOR
) sd_buf
;
1377 if (read_sd (file
, psd
, &sd_size
) <= 0)
1379 debug_printf ("read_sd %E");
1383 get_info_from_sd (psd
, attribute
, uidret
, gidret
);
1388 get_file_attribute (int use_ntsec
, const char *file
,
1389 mode_t
*attribute
, __uid32_t
*uidret
, __gid32_t
*gidret
)
1392 syscall_printf ("file: %s", file
);
1394 if (use_ntsec
&& allow_ntsec
&& wincap
.has_security ())
1396 get_nt_attribute (file
, attribute
, uidret
, gidret
);
1401 *uidret
= myself
->uid
;
1403 *gidret
= myself
->gid
;
1410 int oatt
= *attribute
;
1411 res
= NTReadEA (file
, ".UNIXATTR", (char *)attribute
, sizeof (*attribute
));
1417 return res
> 0 ? 0 : -1;
1421 get_nt_object_attribute (HANDLE handle
, SE_OBJECT_TYPE object_type
,
1422 mode_t
*attribute
, __uid32_t
*uidret
, __gid32_t
*gidret
)
1424 PSECURITY_DESCRIPTOR psd
;
1427 if (object_type
== SE_REGISTRY_KEY
)
1429 /* use different code for registry handles, for performance reasons */
1430 psd
= (PSECURITY_DESCRIPTOR
) & sd_buf
[0];
1431 DWORD len
= sizeof (sd_buf
);
1432 if (ERROR_SUCCESS
!= RegGetKeySecurity ((HKEY
) handle
,
1433 DACL_SECURITY_INFORMATION
|
1434 GROUP_SECURITY_INFORMATION
|
1435 OWNER_SECURITY_INFORMATION
,
1439 debug_printf ("RegGetKeySecurity %E");
1445 if (ERROR_SUCCESS
!= GetSecurityInfo (handle
, object_type
,
1446 DACL_SECURITY_INFORMATION
|
1447 GROUP_SECURITY_INFORMATION
|
1448 OWNER_SECURITY_INFORMATION
,
1449 NULL
, NULL
, NULL
, NULL
, &psd
))
1452 debug_printf ("GetSecurityInfo %E");
1457 get_info_from_sd (psd
, attribute
, uidret
, gidret
);
1458 if (psd
!= (PSECURITY_DESCRIPTOR
) & sd_buf
[0])
1465 get_object_attribute (HANDLE handle
, SE_OBJECT_TYPE object_type
,
1466 mode_t
*attribute
, __uid32_t
*uidret
, __gid32_t
*gidret
)
1468 if (allow_ntsec
&& wincap
.has_security ())
1470 get_nt_object_attribute (handle
, object_type
, attribute
, uidret
, gidret
);
1473 /* The entries are already set to default values */
1478 add_access_allowed_ace (PACL acl
, int offset
, DWORD attributes
,
1479 PSID sid
, size_t &len_add
, DWORD inherit
)
1481 if (!AddAccessAllowedAce (acl
, ACL_REVISION
, attributes
, sid
))
1486 ACCESS_ALLOWED_ACE
*ace
;
1487 if (inherit
&& GetAce (acl
, offset
, (PVOID
*) &ace
))
1488 ace
->Header
.AceFlags
|= inherit
;
1489 len_add
+= sizeof (ACCESS_ALLOWED_ACE
) - sizeof (DWORD
) + GetLengthSid (sid
);
1494 add_access_denied_ace (PACL acl
, int offset
, DWORD attributes
,
1495 PSID sid
, size_t &len_add
, DWORD inherit
)
1497 if (!AddAccessDeniedAce (acl
, ACL_REVISION
, attributes
, sid
))
1502 ACCESS_DENIED_ACE
*ace
;
1503 if (inherit
&& GetAce (acl
, offset
, (PVOID
*) &ace
))
1504 ace
->Header
.AceFlags
|= inherit
;
1505 len_add
+= sizeof (ACCESS_DENIED_ACE
) - sizeof (DWORD
) + GetLengthSid (sid
);
1509 PSECURITY_DESCRIPTOR
1510 alloc_sd (__uid32_t uid
, __gid32_t gid
, int attribute
,
1511 PSECURITY_DESCRIPTOR sd_ret
, DWORD
*sd_size_ret
)
1515 debug_printf("uid %d, gid %d, attribute %x", uid
, gid
, attribute
);
1516 if (!sd_ret
|| !sd_size_ret
)
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");
1530 /* Get SID of owner. */
1532 /* Check for current user first */
1533 if (uid
== myself
->uid
)
1534 owner_sid
= cygheap
->user
.sid ();
1535 else if (uid
== ILLEGAL_UID
)
1536 owner_sid
= cur_owner_sid
;
1537 else if (!owner_sid
.getfrompw (internal_getpwuid (uid
)))
1542 owner_sid
.debug_print ("alloc_sd: owner SID =");
1544 /* Get SID of new group. */
1546 /* Check for current user first */
1547 if (gid
== myself
->gid
)
1548 group_sid
= cygheap
->user
.groups
.pgsid
;
1549 else if (gid
== ILLEGAL_GID
)
1550 group_sid
= cur_group_sid
;
1551 else if (!group_sid
.getfromgr (internal_getgrgid (gid
)))
1556 group_sid
.debug_print ("alloc_sd: group SID =");
1558 /* Initialize local security descriptor. */
1559 SECURITY_DESCRIPTOR sd
;
1560 if (!InitializeSecurityDescriptor (&sd
, SECURITY_DESCRIPTOR_REVISION
))
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
1572 if (wincap
.has_security_descriptor_control ())
1573 SetSecurityDescriptorControl (&sd
, SE_DACL_PROTECTED
, SE_DACL_PROTECTED
);
1575 /* Create owner for local security descriptor. */
1576 if (!SetSecurityDescriptorOwner (&sd
, owner_sid
, FALSE
))
1582 /* Create group for local security descriptor. */
1583 if (!SetSecurityDescriptorGroup (&sd
, group_sid
, FALSE
))
1589 /* Initialize local access control list. */
1591 PACL acl
= (PACL
) acl_buf
;
1592 if (!InitializeAcl (acl
, 3072, ACL_REVISION
))
1598 /* From here fill ACL. */
1599 size_t acl_len
= sizeof (ACL
);
1602 /* Construct allow attribute for owner. */
1603 DWORD owner_allow
= STANDARD_RIGHTS_ALL
1604 | FILE_WRITE_ATTRIBUTES
| FILE_WRITE_EA
;
1605 if (attribute
& S_IRUSR
)
1606 owner_allow
|= FILE_GENERIC_READ
;
1607 if (attribute
& S_IWUSR
)
1608 owner_allow
|= FILE_GENERIC_WRITE
;
1609 if (attribute
& S_IXUSR
)
1610 owner_allow
|= FILE_GENERIC_EXECUTE
;
1611 if (S_ISDIR (attribute
)
1612 && (attribute
& (S_IWUSR
| S_IXUSR
)) == (S_IWUSR
| S_IXUSR
))
1613 owner_allow
|= FILE_DELETE_CHILD
;
1615 /* Construct allow attribute for group. */
1616 DWORD group_allow
= STANDARD_RIGHTS_READ
1617 | FILE_READ_ATTRIBUTES
| FILE_READ_EA
;
1618 if (attribute
& S_IRGRP
)
1619 group_allow
|= FILE_GENERIC_READ
;
1620 if (attribute
& S_IWGRP
)
1621 group_allow
|= STANDARD_RIGHTS_WRITE
| FILE_GENERIC_WRITE
;
1622 if (attribute
& S_IXGRP
)
1623 group_allow
|= FILE_GENERIC_EXECUTE
;
1624 if (S_ISDIR (attribute
)
1625 && (attribute
& (S_IWGRP
| S_IXGRP
)) == (S_IWGRP
| S_IXGRP
)
1626 && !(attribute
& S_ISVTX
))
1627 group_allow
|= FILE_DELETE_CHILD
;
1629 /* Construct allow attribute for everyone. */
1630 DWORD other_allow
= STANDARD_RIGHTS_READ
1631 | FILE_READ_ATTRIBUTES
| FILE_READ_EA
;
1632 if (attribute
& S_IROTH
)
1633 other_allow
|= FILE_GENERIC_READ
;
1634 if (attribute
& S_IWOTH
)
1635 other_allow
|= STANDARD_RIGHTS_WRITE
| FILE_GENERIC_WRITE
;
1636 if (attribute
& S_IXOTH
)
1637 other_allow
|= FILE_GENERIC_EXECUTE
;
1638 if (S_ISDIR (attribute
)
1639 && (attribute
& (S_IWOTH
| S_IXOTH
)) == (S_IWOTH
| S_IXOTH
)
1640 && !(attribute
& S_ISVTX
))
1641 other_allow
|= FILE_DELETE_CHILD
;
1643 /* Construct SUID, SGID and VTX bits in NULL ACE. */
1644 DWORD null_allow
= 0L;
1645 if (attribute
& (S_ISUID
| S_ISGID
| S_ISVTX
))
1647 if (attribute
& S_ISUID
)
1648 null_allow
|= FILE_APPEND_DATA
;
1649 if (attribute
& S_ISGID
)
1650 null_allow
|= FILE_WRITE_DATA
;
1651 if (attribute
& S_ISVTX
)
1652 null_allow
|= FILE_READ_DATA
;
1655 /* Add owner and group permissions if SIDs are equal
1656 and construct deny attributes for group and owner. */
1658 if ((isownergroup
= (owner_sid
== group_sid
)))
1659 owner_allow
|= group_allow
;
1661 DWORD owner_deny
= ~owner_allow
& (group_allow
| other_allow
);
1662 owner_deny
&= ~(STANDARD_RIGHTS_READ
1663 | FILE_READ_ATTRIBUTES
| FILE_READ_EA
1664 | FILE_WRITE_ATTRIBUTES
| FILE_WRITE_EA
);
1666 DWORD group_deny
= ~group_allow
& other_allow
;
1667 group_deny
&= ~(STANDARD_RIGHTS_READ
1668 | FILE_READ_ATTRIBUTES
| FILE_READ_EA
);
1670 /* Set deny ACE for owner. */
1672 && !add_access_denied_ace (acl
, ace_off
++, owner_deny
,
1673 owner_sid
, acl_len
, NO_INHERITANCE
))
1675 /* Set deny ACE for group here to respect the canonical order,
1676 if this does not impact owner */
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
))
1681 /* Set allow ACE for owner. */
1682 if (!add_access_allowed_ace (acl
, ace_off
++, owner_allow
,
1683 owner_sid
, acl_len
, NO_INHERITANCE
))
1685 /* Set deny ACE for group, if still needed. */
1686 if (group_deny
& owner_allow
&& !isownergroup
1687 && !add_access_denied_ace (acl
, ace_off
++, group_deny
,
1688 group_sid
, acl_len
, NO_INHERITANCE
))
1690 /* Set allow ACE for group. */
1692 && !add_access_allowed_ace (acl
, ace_off
++, group_allow
,
1693 group_sid
, acl_len
, NO_INHERITANCE
))
1696 /* Set allow ACE for everyone. */
1697 if (!add_access_allowed_ace (acl
, ace_off
++, other_allow
,
1698 well_known_world_sid
, acl_len
, NO_INHERITANCE
))
1700 /* Set null ACE for special bits. */
1702 && !add_access_allowed_ace (acl
, ace_off
++, null_allow
,
1703 well_known_null_sid
, acl_len
, NO_INHERITANCE
))
1706 /* Fill ACL with unrelated ACEs from current security descriptor. */
1708 BOOL acl_exists
= FALSE
;
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
))
1715 cygpsid
ace_sid ((PSID
) &ace
->SidStart
);
1717 /* Check for related ACEs. */
1718 if (ace_sid
== well_known_null_sid
)
1720 if ((ace_sid
== cur_owner_sid
)
1721 || (ace_sid
== owner_sid
)
1722 || (ace_sid
== cur_group_sid
)
1723 || (ace_sid
== group_sid
)
1724 || (ace_sid
== well_known_world_sid
))
1726 if (ace
->Header
.AceFlags
& SUB_CONTAINERS_AND_OBJECTS_INHERIT
)
1727 ace
->Header
.AceFlags
|= INHERIT_ONLY
;
1732 * Add unrelated ACCESS_DENIED_ACE to the beginning but
1733 * behind the owner_deny, ACCESS_ALLOWED_ACE to the end.
1734 * FIXME: this would break the order of the inherit_only ACEs
1736 if (!AddAce (acl
, ACL_REVISION
,
1737 ace
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
?
1738 (owner_deny
? 1 : 0) : MAXDWORD
,
1739 (LPVOID
) ace
, ace
->Header
.AceSize
))
1744 acl_len
+= ace
->Header
.AceSize
;
1747 /* Construct appropriate inherit attribute for new directories */
1748 if (S_ISDIR (attribute
) && !acl_exists
)
1750 const DWORD inherit
= SUB_CONTAINERS_AND_OBJECTS_INHERIT
| INHERIT_ONLY
;
1752 #if 0 /* FIXME: Not done currently as this breaks the canonical order */
1753 /* Set deny ACE for owner. */
1755 && !add_access_denied_ace (acl
, ace_off
++, owner_deny
,
1756 well_known_creator_owner_sid
, acl_len
, inherit
))
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
))
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
))
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
))
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
))
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
))
1787 /* Set AclSize to computed value. */
1788 acl
->AclSize
= acl_len
;
1789 debug_printf ("ACL-Size: %d", acl_len
);
1791 /* Create DACL for local security descriptor. */
1792 if (!SetSecurityDescriptorDacl (&sd
, TRUE
, acl
, FALSE
))
1798 /* Make self relative security descriptor. */
1800 MakeSelfRelativeSD (&sd
, sd_ret
, sd_size_ret
);
1801 if (*sd_size_ret
<= 0)
1806 if (!MakeSelfRelativeSD (&sd
, sd_ret
, sd_size_ret
))
1811 debug_printf ("Created SD-Size: %d", *sd_size_ret
);
1817 set_security_attribute (int attribute
, PSECURITY_ATTRIBUTES psa
,
1818 void *sd_buf
, DWORD sd_buf_size
)
1820 psa
->lpSecurityDescriptor
= sd_buf
;
1821 InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR
) sd_buf
,
1822 SECURITY_DESCRIPTOR_REVISION
);
1823 psa
->lpSecurityDescriptor
= alloc_sd (geteuid32 (), getegid32 (), attribute
,
1824 (PSECURITY_DESCRIPTOR
) sd_buf
,
1829 set_nt_attribute (const char *file
, __uid32_t uid
, __gid32_t gid
,
1832 if (!wincap
.has_security ())
1835 DWORD sd_size
= 4096;
1837 PSECURITY_DESCRIPTOR psd
= (PSECURITY_DESCRIPTOR
) sd_buf
;
1840 if ((ret
= read_sd (file
, psd
, &sd_size
)) <= 0)
1842 debug_printf ("read_sd %E");
1847 if (!(psd
= alloc_sd (uid
, gid
, attribute
, psd
, &sd_size
)))
1850 return write_sd (file
, psd
, sd_size
);
1854 set_file_attribute (int use_ntsec
, const char *file
,
1855 __uid32_t uid
, __gid32_t gid
, int attribute
)
1859 if (use_ntsec
&& allow_ntsec
)
1860 ret
= set_nt_attribute (file
, uid
, gid
, attribute
);
1861 else if (allow_ntea
&& !NTWriteEA (file
, ".UNIXATTR", (char *) &attribute
,
1862 sizeof (attribute
)))
1867 syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)",
1868 ret
, file
, uid
, gid
, attribute
);
1873 set_file_attribute (int use_ntsec
, const char *file
, int attribute
)
1875 return set_file_attribute (use_ntsec
, file
,
1876 myself
->uid
, myself
->gid
, attribute
);
1880 check_file_access (const char *fn
, int flags
)
1884 DWORD sd_size
= sizeof sd_buf
;
1885 PSECURITY_DESCRIPTOR psd
= (PSECURITY_DESCRIPTOR
) sd_buf
;
1886 HANDLE hToken
, hIToken
;
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
,
1892 FILE_GENERIC_EXECUTE
,
1894 if (read_sd (fn
, psd
, &sd_size
) <= 0)
1897 if (cygheap
->user
.issetuid ())
1898 hToken
= cygheap
->user
.token ();
1899 else if (!OpenProcessToken (hMainProc
, TOKEN_DUPLICATE
, &hToken
))
1904 if (!(status
= DuplicateToken (hToken
, SecurityIdentification
, &hIToken
)))
1906 if (!cygheap
->user
.issetuid ())
1907 CloseHandle (hToken
);
1912 desired
|= FILE_READ_DATA
;
1914 desired
|= FILE_WRITE_DATA
;
1916 desired
|= FILE_EXECUTE
;
1917 if (!AccessCheck (psd
, hIToken
, desired
, &mapping
,
1918 (PPRIVILEGE_SET
) pbuf
, &plength
, &granted
, &status
))
1924 CloseHandle (hIToken
);
1926 debug_printf ("flags %x, ret %d", flags
, ret
);