Cygwin: (mostly) drop NT4 and Samba < 3.0 support
[newlib-cygwin.git] / winsup / cygwin / sec / base.cc
blobd5e39d281aeeb18a1d1563b0f2ed4f54637f6650
1 /* sec/base.cc: NT file access control functions
3 Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de
4 Completely rewritten by Corinna Vinschen <corinna@vinschen.de>
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 details. */
12 #include "winsup.h"
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <cygwin/acl.h>
16 #include "cygerrno.h"
17 #include "security.h"
18 #include "path.h"
19 #include "fhandler.h"
20 #include "dtable.h"
21 #include "pinfo.h"
22 #include "cygheap.h"
23 #include "ntdll.h"
24 #include "tls_pbuf.h"
25 #include <aclapi.h>
27 #define ALL_SECURITY_INFORMATION (DACL_SECURITY_INFORMATION \
28 | GROUP_SECURITY_INFORMATION \
29 | OWNER_SECURITY_INFORMATION)
31 static GENERIC_MAPPING NO_COPY_RO file_mapping = { FILE_GENERIC_READ,
32 FILE_GENERIC_WRITE,
33 FILE_GENERIC_EXECUTE,
34 FILE_ALL_ACCESS };
35 LONG
36 get_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd,
37 bool justcreated)
39 NTSTATUS status = STATUS_SUCCESS;
40 OBJECT_ATTRIBUTES attr;
41 IO_STATUS_BLOCK io;
42 ULONG len = SD_MAXIMUM_SIZE, rlen;
44 /* Allocate space for the security descriptor. */
45 if (!sd.malloc (len))
47 set_errno (ENOMEM);
48 return -1;
50 /* Try to fetch the security descriptor if the handle is valid. */
51 if (fh)
53 status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION,
54 sd, len, &rlen);
55 if (!NT_SUCCESS (status))
56 debug_printf ("NtQuerySecurityObject (%S), status %y",
57 pc.get_nt_native_path (), status);
59 /* If the handle was NULL, or fetching with the original handle didn't work,
60 try to reopen the file with READ_CONTROL and fetch the security descriptor
61 using that handle. */
62 if (!fh || !NT_SUCCESS (status))
64 status = NtOpenFile (&fh, READ_CONTROL,
65 fh ? pc.init_reopen_attr (attr, fh)
66 : pc.get_object_attr (attr, sec_none_nih),
67 &io, FILE_SHARE_VALID_FLAGS,
68 FILE_OPEN_NO_RECALL
69 | FILE_OPEN_FOR_BACKUP_INTENT
70 | pc.is_known_reparse_point ()
71 ? FILE_OPEN_REPARSE_POINT : 0);
72 if (!NT_SUCCESS (status))
74 sd.free ();
75 __seterrno_from_nt_status (status);
76 return -1;
78 status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION,
79 sd, len, &rlen);
80 NtClose (fh);
81 if (!NT_SUCCESS (status))
83 sd.free ();
84 __seterrno_from_nt_status (status);
85 return -1;
88 /* We have a security descriptor now. Unfortunately, if you want to know
89 if an ACE is inherited from the parent object, this isn't sufficient.
91 In the simple case, the SDs control word contains one of the
92 SE_DACL_AUTO_INHERITED or SE_DACL_PROTECTED flags, or at least one of
93 the ACEs has the INHERITED_ACE flag set. In all of these cases we
94 know the DACL has been inherited.
96 If none of these flags is set in the SD, the information whether
97 or not an ACE has been inherited is not available in the DACL of the
98 object. In this case GetSecurityInfo fetches the SD from the parent
99 directory and tests if the object's SD contains inherited ACEs from the
100 parent.
102 Note that we're not testing the SE_DACL_AUTO_INHERITED and
103 SE_DACL_PROTECTED flags here because we know the state the file's SD
104 is in. Since we're creating all files with a NULL descriptor, the DACL
105 is either inherited from the parent, or it's the default DACL. In
106 neither case, one of these flags is set.
108 For speed, we're not calling RtlConvertToAutoInheritSecurityObject
109 anymore (but keep the code here for reference). Rather we just test
110 if one of the parent's ACEs is inheritable. If so, we know we inherited
111 it and set the SE_DACL_AUTO_INHERITED flag. If not, we may assume our
112 object's DACL is the default DACL.
114 This functionality is slow and the extra information is only required
115 when the file has been created and the permissions are about to be set
116 to POSIX permissions. Therefore we only use it in case the file just
117 got created. */
118 if (justcreated)
120 PACL dacl;
121 BOOLEAN exists, def;
122 ACCESS_ALLOWED_ACE *ace;
123 UNICODE_STRING dirname;
124 PSECURITY_DESCRIPTOR psd;
125 tmp_pathbuf tp;
127 /* Open the parent directory with READ_CONTROL... */
128 RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, NULL);
129 InitializeObjectAttributes (&attr, &dirname, pc.objcaseinsensitive (),
130 NULL, NULL);
131 status = NtOpenFile (&fh, READ_CONTROL, &attr, &io,
132 FILE_SHARE_VALID_FLAGS,
133 FILE_OPEN_NO_RECALL
134 | FILE_OPEN_FOR_BACKUP_INTENT
135 | FILE_OPEN_REPARSE_POINT);
136 if (!NT_SUCCESS (status))
138 debug_printf ("NtOpenFile (%S), status %y", &dirname, status);
139 return 0;
141 /* ... fetch the parent's security descriptor ... */
142 psd = (PSECURITY_DESCRIPTOR) tp.w_get ();
143 status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION,
144 psd, len, &rlen);
145 NtClose (fh);
146 if (!NT_SUCCESS (status))
148 debug_printf ("NtQuerySecurityObject (%S), status %y",
149 &dirname, status);
150 return 0;
152 #if 0
153 /* ... and create a new security descriptor in which all inherited ACEs
154 are marked with the INHERITED_ACE flag. For a description of the
155 undocumented RtlConvertToAutoInheritSecurityObject function from
156 ntdll.dll see the MSDN man page for the advapi32 function
157 ConvertToAutoInheritPrivateObjectSecurity. Fortunately the latter
158 is just a shim. */
159 PSECURITY_DESCRIPTOR nsd;
160 status = RtlConvertToAutoInheritSecurityObject (psd, sd, &nsd, NULL,
161 pc.isdir (),
162 &file_mapping);
163 if (!NT_SUCCESS (status))
165 debug_printf ("RtlConvertToAutoInheritSecurityObject (%S), status %y",
166 &dirname, status);
167 return 0;
169 /* Eventually copy the new security descriptor into sd and delete the
170 original one created by RtlConvertToAutoInheritSecurityObject from
171 the heap. */
172 len = RtlLengthSecurityDescriptor (nsd);
173 memcpy ((PSECURITY_DESCRIPTOR) sd, nsd, len);
174 RtlDeleteSecurityObject (&nsd);
175 #else
176 /* ... and check the parent descriptor for inheritable ACEs matching
177 our current object type (file/dir). The simple truth in our case
178 is, either the parent dir had inheritable ACEs and all our ACEs are
179 inherited, or the parent dir didn't have inheritable ACEs and all
180 our ACEs are taken from the default DACL. */
181 bool inherited = false;
182 BYTE search_flags = pc.isdir () ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
183 : SUB_OBJECTS_ONLY_INHERIT;
184 if (NT_SUCCESS (RtlGetDaclSecurityDescriptor (psd, &exists, &dacl, &def))
185 && exists && dacl)
186 for (ULONG idx = 0; idx < dacl->AceCount; ++idx)
187 if (NT_SUCCESS (RtlGetAce (dacl, idx, (PVOID *) &ace))
188 && (ace->Header.AceFlags & search_flags))
190 inherited = true;
191 break;
193 /* Then, if the parent descriptor contained inheritable ACEs, we mark
194 the SD as SE_DACL_AUTO_INHERITED. Note that this requires the
195 matching check in get_posix_access. If we ever revert to
196 RtlConvertToAutoInheritSecurityObject, the check in get_posix_access
197 has to test every single ACE for the INHERITED_ACE flag again. */
198 if (inherited
199 && NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd, &exists, &dacl,
200 &def))
201 && exists && dacl)
202 RtlSetControlSecurityDescriptor (sd, SE_DACL_AUTO_INHERITED,
203 SE_DACL_AUTO_INHERITED);
204 #endif
206 return 0;
209 LONG
210 set_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, bool is_chown)
212 NTSTATUS status = STATUS_SUCCESS;
213 int retry = 0;
214 int res = -1;
216 for (; retry < 2; ++retry)
218 if (fh)
220 status = NtSetSecurityObject (fh,
221 is_chown ? ALL_SECURITY_INFORMATION
222 : DACL_SECURITY_INFORMATION,
223 sd);
224 if (NT_SUCCESS (status))
226 res = 0;
227 break;
230 if (!retry)
232 OBJECT_ATTRIBUTES attr;
233 IO_STATUS_BLOCK io;
234 status = NtOpenFile (&fh, (is_chown ? WRITE_OWNER : 0) | WRITE_DAC,
235 fh ? pc.init_reopen_attr (attr, fh)
236 : pc.get_object_attr (attr, sec_none_nih),
237 &io,
238 FILE_SHARE_VALID_FLAGS,
239 FILE_OPEN_NO_RECALL
240 | FILE_OPEN_FOR_BACKUP_INTENT
241 | pc.is_known_reparse_point ()
242 ? FILE_OPEN_REPARSE_POINT : 0);
243 if (!NT_SUCCESS (status))
245 fh = NULL;
246 break;
250 if (retry && fh)
251 NtClose (fh);
252 if (!NT_SUCCESS (status))
253 __seterrno_from_nt_status (status);
254 return res;
257 static int
258 get_reg_sd (HANDLE handle, security_descriptor &sd_ret)
260 LONG ret;
261 DWORD len = 0;
263 ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION,
264 sd_ret, &len);
265 if (ret == ERROR_INSUFFICIENT_BUFFER)
267 if (!sd_ret.malloc (len))
268 set_errno (ENOMEM);
269 else
270 ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION,
271 sd_ret, &len);
273 if (ret != ERROR_SUCCESS)
275 __seterrno ();
276 return -1;
278 return 0;
282 get_reg_attribute (HKEY hkey, mode_t &attribute, uid_t *uidret,
283 gid_t *gidret)
285 security_descriptor sd;
287 if (!get_reg_sd (hkey, sd))
289 get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
290 return 0;
292 /* The entries are already set to default values */
293 return -1;
297 get_file_attribute (HANDLE handle, path_conv &pc,
298 mode_t &attribute, uid_t *uidret, gid_t *gidret)
300 if (pc.has_acls ())
302 security_descriptor sd;
304 if (!get_file_sd (handle, pc, sd, false))
306 get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
307 return 0;
309 /* ENOSYS is returned by get_file_sd if fetching the DACL from a remote
310 share returns STATUS_INVALID_NETWORK_RESPONSE, which in turn is
311 converted to ERROR_BAD_NET_RESP. This potentially occurs when trying
312 to fetch DACLs from a NT4 machine which is not part of the domain of
313 the requesting machine.
314 FIXME: We dropped NT4 support, but are there other scenarios? */
315 else if (get_errno () != ENOSYS)
317 if (uidret)
318 *uidret = ILLEGAL_UID;
319 if (gidret)
320 *gidret = ILLEGAL_GID;
322 return -1;
326 if (uidret)
327 *uidret = myself->uid;
328 if (gidret)
329 *gidret = myself->gid;
331 return -1;
334 bool
335 add_access_allowed_ace (PACL acl, DWORD attributes, PSID sid, size_t &len_add,
336 DWORD inherit)
338 NTSTATUS status = RtlAddAccessAllowedAceEx (acl, ACL_REVISION, inherit,
339 attributes, sid);
340 if (!NT_SUCCESS (status))
342 __seterrno_from_nt_status (status);
343 return false;
345 len_add += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + RtlLengthSid (sid);
346 return true;
349 bool
350 add_access_denied_ace (PACL acl, DWORD attributes, PSID sid, size_t &len_add,
351 DWORD inherit)
353 NTSTATUS status = RtlAddAccessDeniedAceEx (acl, ACL_REVISION, inherit,
354 attributes, sid);
355 if (!NT_SUCCESS (status))
357 __seterrno_from_nt_status (status);
358 return false;
360 len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + RtlLengthSid (sid);
361 return true;
364 void
365 set_security_attribute (path_conv &pc, int attribute, PSECURITY_ATTRIBUTES psa,
366 security_descriptor &sd)
368 psa->lpSecurityDescriptor = sd.malloc (SECURITY_DESCRIPTOR_MIN_LENGTH);
369 RtlCreateSecurityDescriptor ((PSECURITY_DESCRIPTOR) psa->lpSecurityDescriptor,
370 SECURITY_DESCRIPTOR_REVISION);
371 psa->lpSecurityDescriptor = set_posix_access (attribute, geteuid (),
372 getegid (), NULL, 0,
373 sd, false);
377 get_object_sd (HANDLE handle, security_descriptor &sd)
379 ULONG len = 0;
380 NTSTATUS status;
382 status = NtQuerySecurityObject (handle, ALL_SECURITY_INFORMATION,
383 sd, len, &len);
384 if (status != STATUS_BUFFER_TOO_SMALL)
386 __seterrno_from_nt_status (status);
387 return -1;
389 if (!sd.malloc (len))
391 set_errno (ENOMEM);
392 return -1;
394 status = NtQuerySecurityObject (handle, ALL_SECURITY_INFORMATION,
395 sd, len, &len);
396 if (!NT_SUCCESS (status))
398 __seterrno_from_nt_status (status);
399 return -1;
401 return 0;
405 get_object_attribute (HANDLE handle, uid_t *uidret, gid_t *gidret,
406 mode_t &attribute)
408 security_descriptor sd;
410 if (get_object_sd (handle, sd))
411 return -1;
412 return get_posix_access (sd, attribute, uidret, gidret, NULL, 0)
413 >= 0 ? 0 : -1;
417 create_object_sd_from_attribute (uid_t uid, gid_t gid, mode_t attribute,
418 security_descriptor &sd)
420 return set_posix_access (attribute, uid, gid, NULL, 0, sd, false)
421 ? 0 : -1;
425 set_object_sd (HANDLE handle, security_descriptor &sd, bool chown)
427 NTSTATUS status;
428 status = NtSetSecurityObject (handle, chown ? ALL_SECURITY_INFORMATION
429 : DACL_SECURITY_INFORMATION, sd);
430 if (!NT_SUCCESS (status))
432 __seterrno_from_nt_status (status);
433 return -1;
435 return 0;
439 set_object_attribute (HANDLE handle, uid_t uid, gid_t gid, mode_t attribute)
441 security_descriptor sd;
443 if (create_object_sd_from_attribute (uid, gid, attribute, sd)
444 || set_object_sd (handle, sd, uid != ILLEGAL_UID || gid != ILLEGAL_GID))
445 return -1;
446 return 0;
450 set_created_file_access (HANDLE handle, path_conv &pc, mode_t attr)
452 int ret = -1;
453 security_descriptor sd, sd_ret;
454 mode_t attr_rd;
455 uid_t uid;
456 gid_t gid;
457 tmp_pathbuf tp;
458 aclent_t *aclp;
459 int nentries, idx;
460 bool std_acl;
462 if (!get_file_sd (handle, pc, sd, true))
464 attr |= S_JUSTCREATED;
465 if (pc.isdir ())
466 attr |= S_IFDIR;
467 attr_rd = attr;
468 aclp = (aclent_t *) tp.c_get ();
469 if ((nentries = get_posix_access (sd, attr_rd, &uid, &gid, aclp,
470 MAX_ACL_ENTRIES, &std_acl)) >= 0)
472 if (S_ISLNK (attr))
474 /* Symlinks always get the request POSIX perms. */
475 aclp[0].a_perm = (attr >> 6) & S_IRWXO;
476 if ((idx = searchace (aclp, nentries, GROUP_OBJ)) >= 0)
477 aclp[idx].a_perm = (attr >> 3) & S_IRWXO;
478 if ((idx = searchace (aclp, nentries, CLASS_OBJ)) >= 0)
479 aclp[idx].a_perm = (attr >> 3) & S_IRWXO;
480 if ((idx = searchace (aclp, nentries, OTHER_OBJ)) >= 0)
481 aclp[idx].a_perm = attr & S_IRWXO;
483 else
485 /* Overwrite ACL permissions as required by POSIX 1003.1e
486 draft 17. */
487 aclp[0].a_perm &= (attr >> 6) & S_IRWXO;
488 if ((idx = searchace (aclp, nentries, CLASS_OBJ)) >= 0)
489 aclp[idx].a_perm &= (attr >> 3) & S_IRWXO;
490 if (std_acl
491 && (idx = searchace (aclp, nentries, GROUP_OBJ)) >= 0)
492 aclp[idx].a_perm &= (attr >> 3) & S_IRWXO;
493 if ((idx = searchace (aclp, nentries, OTHER_OBJ)) >= 0)
494 aclp[idx].a_perm &= attr & S_IRWXO;
496 /* Construct appropriate inherit attribute for new directories.
497 Basically we do this only for the sake of non-Cygwin applications.
498 Cygwin applications don't need these. Additionally, if the
499 S_ISGID bit is set, propagate it. */
500 if (S_ISDIR (attr))
502 mode_t def_attr = attr & ~cygheap->umask;
504 if (searchace (aclp, nentries, DEF_USER_OBJ) < 0)
506 aclp[nentries].a_type = DEF_USER_OBJ;
507 aclp[nentries].a_id = ILLEGAL_UID;
508 aclp[nentries++].a_perm = (def_attr >> 6) & S_IRWXO;
510 if (searchace (aclp, nentries, DEF_GROUP_OBJ) < 0)
512 aclp[nentries].a_type = DEF_GROUP_OBJ;
513 aclp[nentries].a_id = ILLEGAL_GID;
514 aclp[nentries++].a_perm = (def_attr >> 3) & S_IRWXO;
516 if (searchace (aclp, nentries, DEF_OTHER_OBJ) < 0)
518 aclp[nentries].a_type = DEF_OTHER_OBJ;
519 aclp[nentries].a_id = ILLEGAL_UID;
520 aclp[nentries++].a_perm = def_attr & S_IRWXO;
522 if (attr_rd & S_ISGID)
523 attr |= S_ISGID;
525 if (set_posix_access (attr, uid, gid, aclp, nentries, sd_ret,
526 pc.fs_is_samba ()))
527 ret = set_file_sd (handle, pc, sd_ret, attr_rd & S_ISGID);
530 return ret;
533 static int
534 check_access (security_descriptor &sd, GENERIC_MAPPING &mapping,
535 ACCESS_MASK desired, int flags, bool effective)
537 int ret = -1;
538 NTSTATUS status, allow;
539 ACCESS_MASK granted;
540 DWORD plen = sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES);
541 PPRIVILEGE_SET pset = (PPRIVILEGE_SET) alloca (plen);
542 HANDLE tok = ((effective && cygheap->user.issetuid ())
543 ? cygheap->user.imp_token ()
544 : hProcImpToken);
546 if (!tok)
548 if (!DuplicateTokenEx (hProcToken, MAXIMUM_ALLOWED, NULL,
549 SecurityImpersonation, TokenImpersonation,
550 &hProcImpToken))
552 __seterrno ();
553 return ret;
555 tok = hProcImpToken;
558 status = NtAccessCheck (sd, tok, desired, &mapping, pset, &plen, &granted,
559 &allow);
560 if (!NT_SUCCESS (status))
561 __seterrno ();
562 else if (!NT_SUCCESS (allow))
564 /* CV, 2006-10-16: Now, that's really weird. Imagine a user who has no
565 standard access to a file, but who has backup and restore privileges
566 and these privileges are enabled in the access token. One would
567 expect that the AccessCheck function takes this into consideration
568 when returning the access status. Otherwise, why bother with the
569 pset parameter, right?
570 But not so. AccessCheck actually returns a status of "false" here,
571 even though opening a file with backup resp. restore intent
572 naturally succeeds for this user. This definitely spoils the results
573 of access(2) for administrative users or the SYSTEM account. So, in
574 case the access check fails, another check against the user's
575 backup/restore privileges has to be made. Sigh. */
576 int granted_flags = 0;
577 BOOLEAN has_priv;
579 if (flags & R_OK)
581 pset->PrivilegeCount = 1;
582 pset->Control = 0;
583 pset->Privilege[0].Luid.HighPart = 0L;
584 pset->Privilege[0].Luid.LowPart = SE_BACKUP_PRIVILEGE;
585 pset->Privilege[0].Attributes = 0;
586 status = NtPrivilegeCheck (tok, pset, &has_priv);
587 if (NT_SUCCESS (status) && has_priv)
588 granted_flags |= R_OK;
590 if (flags & W_OK)
592 pset->PrivilegeCount = 1;
593 pset->Control = 0;
594 pset->Privilege[0].Luid.HighPart = 0L;
595 pset->Privilege[0].Luid.LowPart = SE_RESTORE_PRIVILEGE;
596 pset->Privilege[0].Attributes = 0;
597 status = NtPrivilegeCheck (tok, pset, &has_priv);
598 if (NT_SUCCESS (status) && has_priv)
599 granted_flags |= W_OK;
601 if (granted_flags == flags)
602 ret = 0;
603 else
604 set_errno (EACCES);
606 else
607 ret = 0;
608 return ret;
611 /* Samba override. Check security descriptor for Samba UNIX user and group
612 accounts and check if we have an RFC 2307 mapping to a Windows account.
613 Create a new security descriptor with all of the UNIX accounts with
614 valid mapping replaced with their Windows counterpart. */
615 static void
616 convert_samba_sd (security_descriptor &sd_ret)
618 NTSTATUS status;
619 BOOLEAN dummy;
620 PSID sid;
621 cygsid owner;
622 cygsid group;
623 SECURITY_DESCRIPTOR sd;
624 cyg_ldap cldap;
625 tmp_pathbuf tp;
626 PACL acl, oacl;
627 size_t acl_len;
628 PACCESS_ALLOWED_ACE ace;
630 if (!NT_SUCCESS (RtlGetOwnerSecurityDescriptor (sd_ret, &sid, &dummy)))
631 return;
632 owner = sid;
633 if (!NT_SUCCESS (RtlGetGroupSecurityDescriptor (sd_ret, &sid, &dummy)))
634 return;
635 group = sid;
637 if (sid_id_auth (owner) == 22)
639 struct passwd *pwd;
640 uid_t uid = owner.get_uid (&cldap);
641 if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid)))
642 owner.getfrompw (pwd);
644 if (sid_id_auth (group) == 22)
646 struct group *grp;
647 gid_t gid = group.get_gid (&cldap);
648 if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid)))
649 group.getfromgr (grp);
652 if (!NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd_ret, &dummy,
653 &oacl, &dummy)))
654 return;
655 acl = (PACL) tp.w_get ();
656 RtlCreateAcl (acl, ACL_MAXIMUM_SIZE, ACL_REVISION);
657 acl_len = sizeof (ACL);
659 for (DWORD i = 0; i < oacl->AceCount; ++i)
660 if (NT_SUCCESS (RtlGetAce (oacl, i, (PVOID *) &ace)))
662 cygsid ace_sid ((PSID) &ace->SidStart);
663 if (sid_id_auth (ace_sid) == 22)
665 if (sid_sub_auth (ace_sid, 0) == 1) /* user */
667 struct passwd *pwd;
668 uid_t uid = ace_sid.get_uid (&cldap);
669 if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid)))
670 ace_sid.getfrompw (pwd);
672 else if (sid_sub_auth (ace_sid, 0) == 2) /* group */
674 struct group *grp;
675 gid_t gid = ace_sid.get_gid (&cldap);
676 if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid)))
677 ace_sid.getfromgr (grp);
680 if (!add_access_allowed_ace (acl, ace->Mask, ace_sid, acl_len,
681 ace->Header.AceFlags))
682 return;
684 acl->AclSize = acl_len;
686 RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
687 RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
688 RtlSetOwnerSecurityDescriptor (&sd, owner, FALSE);
689 RtlSetGroupSecurityDescriptor (&sd, group, FALSE);
691 status = RtlSetDaclSecurityDescriptor (&sd, TRUE, acl, FALSE);
692 if (!NT_SUCCESS (status))
693 return;
694 DWORD sd_size = 0;
695 status = RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size);
696 if (sd_size > 0 && sd_ret.malloc (sd_size))
697 RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size);
701 check_file_access (path_conv &pc, int flags, bool effective)
703 security_descriptor sd;
704 int ret = -1;
705 ACCESS_MASK desired = 0;
706 if (flags & R_OK)
707 desired |= FILE_READ_DATA;
708 if (flags & W_OK)
709 desired |= FILE_WRITE_DATA;
710 if (flags & X_OK)
711 desired |= FILE_EXECUTE;
712 if (!get_file_sd (pc.handle (), pc, sd, false))
714 /* Tweak Samba security descriptor as necessary. */
715 if (pc.fs_is_samba ())
716 convert_samba_sd (sd);
717 ret = check_access (sd, file_mapping, desired, flags, effective);
719 debug_printf ("flags %y, ret %d", flags, ret);
720 return ret;
724 check_registry_access (HANDLE hdl, int flags, bool effective)
726 security_descriptor sd;
727 int ret = -1;
728 static GENERIC_MAPPING NO_COPY_RO reg_mapping = { KEY_READ,
729 KEY_WRITE,
730 KEY_EXECUTE,
731 KEY_ALL_ACCESS };
732 ACCESS_MASK desired = 0;
733 if (flags & R_OK)
734 desired |= KEY_ENUMERATE_SUB_KEYS;
735 if (flags & W_OK)
736 desired |= KEY_SET_VALUE;
737 if (flags & X_OK)
738 desired |= KEY_QUERY_VALUE;
740 if ((HKEY) hdl == HKEY_PERFORMANCE_DATA)
741 /* RegGetKeySecurity() always fails with ERROR_INVALID_HANDLE. */
742 ret = 0;
743 else if (!get_reg_sd (hdl, sd))
744 ret = check_access (sd, reg_mapping, desired, flags, effective);
746 /* As long as we can't write the registry... */
747 if (flags & W_OK)
749 set_errno (EROFS);
750 ret = -1;
752 debug_printf ("flags %y, ret %d", flags, ret);
753 return ret;