Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / sec / base.cc
blob8b04b40b4943ea32b3dcfcb630d55e930bb68f0a
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_FOR_BACKUP_INTENT
69 | pc.is_known_reparse_point ()
70 ? FILE_OPEN_REPARSE_POINT : 0);
71 if (!NT_SUCCESS (status))
73 sd.free ();
74 __seterrno_from_nt_status (status);
75 return -1;
77 status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION,
78 sd, len, &rlen);
79 NtClose (fh);
80 if (!NT_SUCCESS (status))
82 sd.free ();
83 __seterrno_from_nt_status (status);
84 return -1;
87 /* We have a security descriptor now. Unfortunately, if you want to know
88 if an ACE is inherited from the parent object, this isn't sufficient.
90 In the simple case, the SDs control word contains one of the
91 SE_DACL_AUTO_INHERITED or SE_DACL_PROTECTED flags, or at least one of
92 the ACEs has the INHERITED_ACE flag set. In all of these cases we
93 know the DACL has been inherited.
95 If none of these flags is set in the SD, the information whether
96 or not an ACE has been inherited is not available in the DACL of the
97 object. In this case GetSecurityInfo fetches the SD from the parent
98 directory and tests if the object's SD contains inherited ACEs from the
99 parent.
101 Note that we're not testing the SE_DACL_AUTO_INHERITED and
102 SE_DACL_PROTECTED flags here because we know the state the file's SD
103 is in. Since we're creating all files with a NULL descriptor, the DACL
104 is either inherited from the parent, or it's the default DACL. In
105 neither case, one of these flags is set.
107 For speed, we're not calling RtlConvertToAutoInheritSecurityObject
108 anymore (but keep the code here for reference). Rather we just test
109 if one of the parent's ACEs is inheritable. If so, we know we inherited
110 it and set the SE_DACL_AUTO_INHERITED flag. If not, we may assume our
111 object's DACL is the default DACL.
113 This functionality is slow and the extra information is only required
114 when the file has been created and the permissions are about to be set
115 to POSIX permissions. Therefore we only use it in case the file just
116 got created. */
117 if (justcreated)
119 PACL dacl;
120 BOOLEAN exists, def;
121 ACCESS_ALLOWED_ACE *ace;
122 UNICODE_STRING dirname;
123 PSECURITY_DESCRIPTOR psd;
124 tmp_pathbuf tp;
126 /* Open the parent directory with READ_CONTROL... */
127 RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, NULL);
128 InitializeObjectAttributes (&attr, &dirname, pc.objcaseinsensitive (),
129 NULL, NULL);
130 status = NtOpenFile (&fh, READ_CONTROL, &attr, &io,
131 FILE_SHARE_VALID_FLAGS,
132 FILE_OPEN_FOR_BACKUP_INTENT
133 | FILE_OPEN_REPARSE_POINT);
134 if (!NT_SUCCESS (status))
136 debug_printf ("NtOpenFile (%S), status %y", &dirname, status);
137 return 0;
139 /* ... fetch the parent's security descriptor ... */
140 psd = (PSECURITY_DESCRIPTOR) tp.w_get ();
141 status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION,
142 psd, len, &rlen);
143 NtClose (fh);
144 if (!NT_SUCCESS (status))
146 debug_printf ("NtQuerySecurityObject (%S), status %y",
147 &dirname, status);
148 return 0;
150 #if 0
151 /* ... and create a new security descriptor in which all inherited ACEs
152 are marked with the INHERITED_ACE flag. For a description of the
153 undocumented RtlConvertToAutoInheritSecurityObject function from
154 ntdll.dll see the MSDN man page for the advapi32 function
155 ConvertToAutoInheritPrivateObjectSecurity. Fortunately the latter
156 is just a shim. */
157 PSECURITY_DESCRIPTOR nsd;
158 status = RtlConvertToAutoInheritSecurityObject (psd, sd, &nsd, NULL,
159 pc.isdir (),
160 &file_mapping);
161 if (!NT_SUCCESS (status))
163 debug_printf ("RtlConvertToAutoInheritSecurityObject (%S), status %y",
164 &dirname, status);
165 return 0;
167 /* Eventually copy the new security descriptor into sd and delete the
168 original one created by RtlConvertToAutoInheritSecurityObject from
169 the heap. */
170 len = RtlLengthSecurityDescriptor (nsd);
171 memcpy ((PSECURITY_DESCRIPTOR) sd, nsd, len);
172 RtlDeleteSecurityObject (&nsd);
173 #else
174 /* ... and check the parent descriptor for inheritable ACEs matching
175 our current object type (file/dir). The simple truth in our case
176 is, either the parent dir had inheritable ACEs and all our ACEs are
177 inherited, or the parent dir didn't have inheritable ACEs and all
178 our ACEs are taken from the default DACL. */
179 bool inherited = false;
180 BYTE search_flags = pc.isdir () ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
181 : SUB_OBJECTS_ONLY_INHERIT;
182 if (NT_SUCCESS (RtlGetDaclSecurityDescriptor (psd, &exists, &dacl, &def))
183 && exists && dacl)
184 for (ULONG idx = 0; idx < dacl->AceCount; ++idx)
185 if (NT_SUCCESS (RtlGetAce (dacl, idx, (PVOID *) &ace))
186 && (ace->Header.AceFlags & search_flags))
188 inherited = true;
189 break;
191 /* Then, if the parent descriptor contained inheritable ACEs, we mark
192 the SD as SE_DACL_AUTO_INHERITED. Note that this requires the
193 matching check in get_posix_access. If we ever revert to
194 RtlConvertToAutoInheritSecurityObject, the check in get_posix_access
195 has to test every single ACE for the INHERITED_ACE flag again. */
196 if (inherited
197 && NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd, &exists, &dacl,
198 &def))
199 && exists && dacl)
200 RtlSetControlSecurityDescriptor (sd, SE_DACL_AUTO_INHERITED,
201 SE_DACL_AUTO_INHERITED);
202 #endif
204 return 0;
207 LONG
208 set_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, bool is_chown)
210 NTSTATUS status = STATUS_SUCCESS;
211 int retry = 0;
212 int res = -1;
214 for (; retry < 2; ++retry)
216 if (fh)
218 status = NtSetSecurityObject (fh,
219 is_chown ? ALL_SECURITY_INFORMATION
220 : DACL_SECURITY_INFORMATION,
221 sd);
222 if (NT_SUCCESS (status))
224 res = 0;
225 break;
228 if (!retry)
230 OBJECT_ATTRIBUTES attr;
231 IO_STATUS_BLOCK io;
232 status = NtOpenFile (&fh, (is_chown ? WRITE_OWNER : 0) | WRITE_DAC,
233 fh ? pc.init_reopen_attr (attr, fh)
234 : pc.get_object_attr (attr, sec_none_nih),
235 &io,
236 FILE_SHARE_VALID_FLAGS,
237 FILE_OPEN_FOR_BACKUP_INTENT
238 | pc.is_known_reparse_point ()
239 ? FILE_OPEN_REPARSE_POINT : 0);
240 if (!NT_SUCCESS (status))
242 fh = NULL;
243 break;
247 if (retry && fh)
248 NtClose (fh);
249 if (!NT_SUCCESS (status))
250 __seterrno_from_nt_status (status);
251 return res;
254 static int
255 get_reg_sd (HANDLE handle, security_descriptor &sd_ret)
257 LONG ret;
258 DWORD len = 0;
260 ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION,
261 sd_ret, &len);
262 if (ret == ERROR_INSUFFICIENT_BUFFER)
264 if (!sd_ret.malloc (len))
265 set_errno (ENOMEM);
266 else
267 ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION,
268 sd_ret, &len);
270 if (ret != ERROR_SUCCESS)
272 __seterrno ();
273 return -1;
275 return 0;
279 get_reg_attribute (HKEY hkey, mode_t &attribute, uid_t *uidret,
280 gid_t *gidret)
282 security_descriptor sd;
284 if (!get_reg_sd (hkey, sd))
286 get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
287 return 0;
289 /* The entries are already set to default values */
290 return -1;
294 get_file_attribute (HANDLE handle, path_conv &pc,
295 mode_t &attribute, uid_t *uidret, gid_t *gidret)
297 if (pc.has_acls ())
299 security_descriptor sd;
301 if (!get_file_sd (handle, pc, sd, false))
303 get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
304 return 0;
306 /* ENOSYS is returned by get_file_sd if fetching the DACL from a remote
307 share returns STATUS_INVALID_NETWORK_RESPONSE, which in turn is
308 converted to ERROR_BAD_NET_RESP. This potentially occurs when trying
309 to fetch DACLs from a NT4 machine which is not part of the domain of
310 the requesting machine. */
311 else if (get_errno () != ENOSYS)
313 if (uidret)
314 *uidret = ILLEGAL_UID;
315 if (gidret)
316 *gidret = ILLEGAL_GID;
318 return -1;
322 if (uidret)
323 *uidret = myself->uid;
324 if (gidret)
325 *gidret = myself->gid;
327 return -1;
330 bool
331 add_access_allowed_ace (PACL acl, DWORD attributes, PSID sid, size_t &len_add,
332 DWORD inherit)
334 NTSTATUS status = RtlAddAccessAllowedAceEx (acl, ACL_REVISION, inherit,
335 attributes, sid);
336 if (!NT_SUCCESS (status))
338 __seterrno_from_nt_status (status);
339 return false;
341 len_add += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + RtlLengthSid (sid);
342 return true;
345 bool
346 add_access_denied_ace (PACL acl, DWORD attributes, PSID sid, size_t &len_add,
347 DWORD inherit)
349 NTSTATUS status = RtlAddAccessDeniedAceEx (acl, ACL_REVISION, inherit,
350 attributes, sid);
351 if (!NT_SUCCESS (status))
353 __seterrno_from_nt_status (status);
354 return false;
356 len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + RtlLengthSid (sid);
357 return true;
360 void
361 set_security_attribute (path_conv &pc, int attribute, PSECURITY_ATTRIBUTES psa,
362 security_descriptor &sd)
364 psa->lpSecurityDescriptor = sd.malloc (SECURITY_DESCRIPTOR_MIN_LENGTH);
365 RtlCreateSecurityDescriptor ((PSECURITY_DESCRIPTOR) psa->lpSecurityDescriptor,
366 SECURITY_DESCRIPTOR_REVISION);
367 psa->lpSecurityDescriptor = set_posix_access (attribute, geteuid (),
368 getegid (), NULL, 0,
369 sd, false);
373 get_object_sd (HANDLE handle, security_descriptor &sd)
375 ULONG len = 0;
376 NTSTATUS status;
378 status = NtQuerySecurityObject (handle, ALL_SECURITY_INFORMATION,
379 sd, len, &len);
380 if (status != STATUS_BUFFER_TOO_SMALL)
382 __seterrno_from_nt_status (status);
383 return -1;
385 if (!sd.malloc (len))
387 set_errno (ENOMEM);
388 return -1;
390 status = NtQuerySecurityObject (handle, ALL_SECURITY_INFORMATION,
391 sd, len, &len);
392 if (!NT_SUCCESS (status))
394 __seterrno_from_nt_status (status);
395 return -1;
397 return 0;
401 get_object_attribute (HANDLE handle, uid_t *uidret, gid_t *gidret,
402 mode_t &attribute)
404 security_descriptor sd;
406 if (get_object_sd (handle, sd))
407 return -1;
408 return get_posix_access (sd, attribute, uidret, gidret, NULL, 0)
409 >= 0 ? 0 : -1;
413 create_object_sd_from_attribute (uid_t uid, gid_t gid, mode_t attribute,
414 security_descriptor &sd)
416 return set_posix_access (attribute, uid, gid, NULL, 0, sd, false)
417 ? 0 : -1;
421 set_object_sd (HANDLE handle, security_descriptor &sd, bool chown)
423 NTSTATUS status;
424 status = NtSetSecurityObject (handle, chown ? ALL_SECURITY_INFORMATION
425 : DACL_SECURITY_INFORMATION, sd);
426 if (!NT_SUCCESS (status))
428 __seterrno_from_nt_status (status);
429 return -1;
431 return 0;
435 set_object_attribute (HANDLE handle, uid_t uid, gid_t gid, mode_t attribute)
437 security_descriptor sd;
439 if (create_object_sd_from_attribute (uid, gid, attribute, sd)
440 || set_object_sd (handle, sd, uid != ILLEGAL_UID || gid != ILLEGAL_GID))
441 return -1;
442 return 0;
446 set_created_file_access (HANDLE handle, path_conv &pc, mode_t attr)
448 int ret = -1;
449 security_descriptor sd, sd_ret;
450 mode_t attr_rd;
451 uid_t uid;
452 gid_t gid;
453 tmp_pathbuf tp;
454 aclent_t *aclp;
455 int nentries, idx;
456 bool std_acl;
458 if (!get_file_sd (handle, pc, sd, true))
460 attr |= S_JUSTCREATED;
461 if (pc.isdir ())
462 attr |= S_IFDIR;
463 attr_rd = attr;
464 aclp = (aclent_t *) tp.c_get ();
465 if ((nentries = get_posix_access (sd, attr_rd, &uid, &gid, aclp,
466 MAX_ACL_ENTRIES, &std_acl)) >= 0)
468 if (S_ISLNK (attr))
470 /* Symlinks always get the request POSIX perms. */
471 aclp[0].a_perm = (attr >> 6) & S_IRWXO;
472 if ((idx = searchace (aclp, nentries, GROUP_OBJ)) >= 0)
473 aclp[idx].a_perm = (attr >> 3) & S_IRWXO;
474 if ((idx = searchace (aclp, nentries, CLASS_OBJ)) >= 0)
475 aclp[idx].a_perm = (attr >> 3) & S_IRWXO;
476 if ((idx = searchace (aclp, nentries, OTHER_OBJ)) >= 0)
477 aclp[idx].a_perm = attr & S_IRWXO;
479 else
481 /* Overwrite ACL permissions as required by POSIX 1003.1e
482 draft 17. */
483 aclp[0].a_perm &= (attr >> 6) & S_IRWXO;
484 if ((idx = searchace (aclp, nentries, CLASS_OBJ)) >= 0)
485 aclp[idx].a_perm &= (attr >> 3) & S_IRWXO;
486 if (std_acl
487 && (idx = searchace (aclp, nentries, GROUP_OBJ)) >= 0)
488 aclp[idx].a_perm &= (attr >> 3) & S_IRWXO;
489 if ((idx = searchace (aclp, nentries, OTHER_OBJ)) >= 0)
490 aclp[idx].a_perm &= attr & S_IRWXO;
492 /* Construct appropriate inherit attribute for new directories.
493 Basically we do this only for the sake of non-Cygwin applications.
494 Cygwin applications don't need these. Additionally, if the
495 S_ISGID bit is set, propagate it. */
496 if (S_ISDIR (attr))
498 mode_t def_attr = attr & ~cygheap->umask;
500 if (searchace (aclp, nentries, DEF_USER_OBJ) < 0)
502 aclp[nentries].a_type = DEF_USER_OBJ;
503 aclp[nentries].a_id = ILLEGAL_UID;
504 aclp[nentries++].a_perm = (def_attr >> 6) & S_IRWXO;
506 if (searchace (aclp, nentries, DEF_GROUP_OBJ) < 0)
508 aclp[nentries].a_type = DEF_GROUP_OBJ;
509 aclp[nentries].a_id = ILLEGAL_GID;
510 aclp[nentries++].a_perm = (def_attr >> 3) & S_IRWXO;
512 if (searchace (aclp, nentries, DEF_OTHER_OBJ) < 0)
514 aclp[nentries].a_type = DEF_OTHER_OBJ;
515 aclp[nentries].a_id = ILLEGAL_UID;
516 aclp[nentries++].a_perm = def_attr & S_IRWXO;
518 if (attr_rd & S_ISGID)
519 attr |= S_ISGID;
521 if (set_posix_access (attr, uid, gid, aclp, nentries, sd_ret,
522 pc.fs_is_samba ()))
523 ret = set_file_sd (handle, pc, sd_ret, attr_rd & S_ISGID);
526 return ret;
529 static int
530 check_access (security_descriptor &sd, GENERIC_MAPPING &mapping,
531 ACCESS_MASK desired, int flags, bool effective)
533 int ret = -1;
534 NTSTATUS status, allow;
535 ACCESS_MASK granted;
536 DWORD plen = sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES);
537 PPRIVILEGE_SET pset = (PPRIVILEGE_SET) alloca (plen);
538 HANDLE tok = ((effective && cygheap->user.issetuid ())
539 ? cygheap->user.imp_token ()
540 : hProcImpToken);
542 if (!tok)
544 if (!DuplicateTokenEx (hProcToken, MAXIMUM_ALLOWED, NULL,
545 SecurityImpersonation, TokenImpersonation,
546 &hProcImpToken))
548 __seterrno ();
549 return ret;
551 tok = hProcImpToken;
554 status = NtAccessCheck (sd, tok, desired, &mapping, pset, &plen, &granted,
555 &allow);
556 if (!NT_SUCCESS (status))
557 __seterrno ();
558 else if (!NT_SUCCESS (allow))
560 /* CV, 2006-10-16: Now, that's really weird. Imagine a user who has no
561 standard access to a file, but who has backup and restore privileges
562 and these privileges are enabled in the access token. One would
563 expect that the AccessCheck function takes this into consideration
564 when returning the access status. Otherwise, why bother with the
565 pset parameter, right?
566 But not so. AccessCheck actually returns a status of "false" here,
567 even though opening a file with backup resp. restore intent
568 naturally succeeds for this user. This definitely spoils the results
569 of access(2) for administrative users or the SYSTEM account. So, in
570 case the access check fails, another check against the user's
571 backup/restore privileges has to be made. Sigh. */
572 int granted_flags = 0;
573 BOOLEAN has_priv;
575 if (flags & R_OK)
577 pset->PrivilegeCount = 1;
578 pset->Control = 0;
579 pset->Privilege[0].Luid.HighPart = 0L;
580 pset->Privilege[0].Luid.LowPart = SE_BACKUP_PRIVILEGE;
581 pset->Privilege[0].Attributes = 0;
582 status = NtPrivilegeCheck (tok, pset, &has_priv);
583 if (NT_SUCCESS (status) && has_priv)
584 granted_flags |= R_OK;
586 if (flags & W_OK)
588 pset->PrivilegeCount = 1;
589 pset->Control = 0;
590 pset->Privilege[0].Luid.HighPart = 0L;
591 pset->Privilege[0].Luid.LowPart = SE_RESTORE_PRIVILEGE;
592 pset->Privilege[0].Attributes = 0;
593 status = NtPrivilegeCheck (tok, pset, &has_priv);
594 if (NT_SUCCESS (status) && has_priv)
595 granted_flags |= W_OK;
597 if (granted_flags == flags)
598 ret = 0;
599 else
600 set_errno (EACCES);
602 else
603 ret = 0;
604 return ret;
607 /* Samba override. Check security descriptor for Samba UNIX user and group
608 accounts and check if we have an RFC 2307 mapping to a Windows account.
609 Create a new security descriptor with all of the UNIX accounts with
610 valid mapping replaced with their Windows counterpart. */
611 static void
612 convert_samba_sd (security_descriptor &sd_ret)
614 NTSTATUS status;
615 BOOLEAN dummy;
616 PSID sid;
617 cygsid owner;
618 cygsid group;
619 SECURITY_DESCRIPTOR sd;
620 cyg_ldap cldap;
621 tmp_pathbuf tp;
622 PACL acl, oacl;
623 size_t acl_len;
624 PACCESS_ALLOWED_ACE ace;
626 if (!NT_SUCCESS (RtlGetOwnerSecurityDescriptor (sd_ret, &sid, &dummy)))
627 return;
628 owner = sid;
629 if (!NT_SUCCESS (RtlGetGroupSecurityDescriptor (sd_ret, &sid, &dummy)))
630 return;
631 group = sid;
633 if (sid_id_auth (owner) == 22)
635 struct passwd *pwd;
636 uid_t uid = owner.get_uid (&cldap);
637 if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid)))
638 owner.getfrompw (pwd);
640 if (sid_id_auth (group) == 22)
642 struct group *grp;
643 gid_t gid = group.get_gid (&cldap);
644 if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid)))
645 group.getfromgr (grp);
648 if (!NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd_ret, &dummy,
649 &oacl, &dummy)))
650 return;
651 acl = (PACL) tp.w_get ();
652 RtlCreateAcl (acl, ACL_MAXIMUM_SIZE, ACL_REVISION);
653 acl_len = sizeof (ACL);
655 for (DWORD i = 0; i < oacl->AceCount; ++i)
656 if (NT_SUCCESS (RtlGetAce (oacl, i, (PVOID *) &ace)))
658 cygsid ace_sid ((PSID) &ace->SidStart);
659 if (sid_id_auth (ace_sid) == 22)
661 if (sid_sub_auth (ace_sid, 0) == 1) /* user */
663 struct passwd *pwd;
664 uid_t uid = ace_sid.get_uid (&cldap);
665 if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid)))
666 ace_sid.getfrompw (pwd);
668 else if (sid_sub_auth (ace_sid, 0) == 2) /* group */
670 struct group *grp;
671 gid_t gid = ace_sid.get_gid (&cldap);
672 if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid)))
673 ace_sid.getfromgr (grp);
676 if (!add_access_allowed_ace (acl, ace->Mask, ace_sid, acl_len,
677 ace->Header.AceFlags))
678 return;
680 acl->AclSize = acl_len;
682 RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
683 RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
684 RtlSetOwnerSecurityDescriptor (&sd, owner, FALSE);
685 RtlSetGroupSecurityDescriptor (&sd, group, FALSE);
687 status = RtlSetDaclSecurityDescriptor (&sd, TRUE, acl, FALSE);
688 if (!NT_SUCCESS (status))
689 return;
690 DWORD sd_size = 0;
691 status = RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size);
692 if (sd_size > 0 && sd_ret.malloc (sd_size))
693 RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size);
697 check_file_access (path_conv &pc, int flags, bool effective)
699 security_descriptor sd;
700 int ret = -1;
701 ACCESS_MASK desired = 0;
702 if (flags & R_OK)
703 desired |= FILE_READ_DATA;
704 if (flags & W_OK)
705 desired |= FILE_WRITE_DATA;
706 if (flags & X_OK)
707 desired |= FILE_EXECUTE;
708 if (!get_file_sd (pc.handle (), pc, sd, false))
710 /* Tweak Samba security descriptor as necessary. */
711 if (pc.fs_is_samba ())
712 convert_samba_sd (sd);
713 ret = check_access (sd, file_mapping, desired, flags, effective);
715 debug_printf ("flags %y, ret %d", flags, ret);
716 return ret;
720 check_registry_access (HANDLE hdl, int flags, bool effective)
722 security_descriptor sd;
723 int ret = -1;
724 static GENERIC_MAPPING NO_COPY_RO reg_mapping = { KEY_READ,
725 KEY_WRITE,
726 KEY_EXECUTE,
727 KEY_ALL_ACCESS };
728 ACCESS_MASK desired = 0;
729 if (flags & R_OK)
730 desired |= KEY_ENUMERATE_SUB_KEYS;
731 if (flags & W_OK)
732 desired |= KEY_SET_VALUE;
733 if (flags & X_OK)
734 desired |= KEY_QUERY_VALUE;
736 if ((HKEY) hdl == HKEY_PERFORMANCE_DATA)
737 /* RegGetKeySecurity() always fails with ERROR_INVALID_HANDLE. */
738 ret = 0;
739 else if (!get_reg_sd (hdl, sd))
740 ret = check_access (sd, reg_mapping, desired, flags, effective);
742 /* As long as we can't write the registry... */
743 if (flags & W_OK)
745 set_errno (EROFS);
746 ret = -1;
748 debug_printf ("flags %y, ret %d", flags, ret);
749 return ret;