📄 sec_acl.cc
字号:
/* secacl.cc: Sun compatible ACL functions. Copyright 2000, 2001, 2002 Red Hat, Inc. Written by Corinna Vinschen <corinna@vinschen.de>This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license. Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#include <grp.h>#include <pwd.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <limits.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/acl.h>#include <ctype.h>#include <wingdi.h>#include <winuser.h>#include "cygerrno.h"#include "security.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "pinfo.h"#include "cygheap.h"extern "C" int aclsort (int nentries, int, __aclent16_t *aclbufp);extern "C" int acl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp);static intsearchace (__aclent16_t *aclp, int nentries, int type, int id = -1){ int i; for (i = 0; i < nentries; ++i) if ((aclp[i].a_type == type && (id < 0 || aclp[i].a_id == id)) || !aclp[i].a_type) return i; return -1;}static intsetacl (const char *file, int nentries, __aclent16_t *aclbufp){ DWORD sd_size = 4096; char sd_buf[4096]; PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; if (read_sd (file, psd, &sd_size) <= 0) { debug_printf ("read_sd %E"); return -1; } BOOL dummy; /* Get owner SID. */ PSID owner_sid = NULL; if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) { __seterrno (); return -1; } cygsid owner (owner_sid); /* Get group SID. */ PSID group_sid = NULL; if (!GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) { __seterrno (); return -1; } cygsid group (group_sid); /* Initialize local security descriptor. */ SECURITY_DESCRIPTOR sd; if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) { __seterrno (); return -1; } if (!SetSecurityDescriptorOwner (&sd, owner, FALSE)) { __seterrno (); return -1; } if (group && !SetSecurityDescriptorGroup (&sd, group, FALSE)) { __seterrno (); return -1; } /* Fill access control list. */ char acl_buf[3072]; PACL acl = (PACL) acl_buf; size_t acl_len = sizeof (ACL); int ace_off = 0; cygsid sid; struct passwd *pw; struct __group32 *gr; int pos; if (!InitializeAcl (acl, 3072, ACL_REVISION)) { __seterrno (); return -1; } for (int i = 0; i < nentries; ++i) { DWORD allow = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA; if (aclbufp[i].a_perm & S_IROTH) allow |= FILE_GENERIC_READ; if (aclbufp[i].a_perm & S_IWOTH) allow |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE; if (aclbufp[i].a_perm & S_IXOTH) allow |= FILE_GENERIC_EXECUTE; if ((aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH)) allow |= FILE_DELETE_CHILD; /* Set inherit property. */ DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT) ? (SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY) : NO_INHERITANCE; /* * If a specific acl contains a corresponding default entry with * identical permissions, only one Windows ACE with proper * inheritance bits is created. */ if (!(aclbufp[i].a_type & ACL_DEFAULT) && (pos = searchace (aclbufp, nentries, aclbufp[i].a_type | ACL_DEFAULT, (aclbufp[i].a_type & (USER|GROUP)) ? aclbufp[i].a_id : -1)) >= 0 && aclbufp[pos].a_type && aclbufp[i].a_perm == aclbufp[pos].a_perm) { inheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; /* This eliminates the corresponding default entry. */ aclbufp[pos].a_type = 0; } switch (aclbufp[i].a_type) { case USER_OBJ: case DEF_USER_OBJ: allow |= STANDARD_RIGHTS_ALL & ~DELETE; if (!add_access_allowed_ace (acl, ace_off++, allow, owner, acl_len, inheritance)) return -1; break; case USER: case DEF_USER: if (!(pw = getpwuid32 (aclbufp[i].a_id)) || !sid.getfrompw (pw) || !add_access_allowed_ace (acl, ace_off++, allow, sid, acl_len, inheritance)) return -1; break; case GROUP_OBJ: case DEF_GROUP_OBJ: if (!add_access_allowed_ace (acl, ace_off++, allow, group, acl_len, inheritance)) return -1; break; case GROUP: case DEF_GROUP: if (!(gr = getgrgid32 (aclbufp[i].a_id)) || !sid.getfromgr (gr) || !add_access_allowed_ace (acl, ace_off++, allow, sid, acl_len, inheritance)) return -1; break; case OTHER_OBJ: case DEF_OTHER_OBJ: if (!add_access_allowed_ace (acl, ace_off++, allow, well_known_world_sid, acl_len, inheritance)) return -1; break; } } /* Set AclSize to computed value. */ acl->AclSize = acl_len; debug_printf ("ACL-Size: %d", acl_len); /* Create DACL for local security descriptor. */ if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) { __seterrno (); return -1; } /* Make self relative security descriptor in psd. */ sd_size = 0; MakeSelfRelativeSD (&sd, psd, &sd_size); if (sd_size <= 0) { __seterrno (); return -1; } if (!MakeSelfRelativeSD (&sd, psd, &sd_size)) { __seterrno (); return -1; } debug_printf ("Created SD-Size: %d", sd_size); return write_sd (file, psd, sd_size);}/* Temporary access denied bits */#define DENY_R 040000#define DENY_W 020000#define DENY_X 010000static voidgetace (__aclent16_t &acl, int type, int id, DWORD win_ace_mask, DWORD win_ace_type){ acl.a_type = type; acl.a_id = id; if ((win_ace_mask & FILE_READ_DATA) && !(acl.a_perm & (S_IROTH | DENY_R))) if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) acl.a_perm |= S_IROTH; else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) acl.a_perm |= DENY_R; if ((win_ace_mask & FILE_WRITE_DATA) && !(acl.a_perm & (S_IWOTH | DENY_W))) if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) acl.a_perm |= S_IWOTH; else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) acl.a_perm |= DENY_W; if ((win_ace_mask & FILE_EXECUTE) && !(acl.a_perm & (S_IXOTH | DENY_X))) if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) acl.a_perm |= S_IXOTH; else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) acl.a_perm |= DENY_X;}static intgetacl (const char *file, DWORD attr, int nentries, __aclent16_t *aclbufp){ DWORD sd_size = 4096; char sd_buf[4096]; PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; int ret; if ((ret = read_sd (file, psd, &sd_size)) <= 0) { debug_printf ("read_sd %E"); return ret; } PSID owner_sid; PSID group_sid; BOOL dummy; __uid32_t uid; __gid32_t gid; if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) { debug_printf ("GetSecurityDescriptorOwner %E"); __seterrno (); return -1; } uid = cygsid (owner_sid).get_uid (); if (!GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) { debug_printf ("GetSecurityDescriptorGroup %E"); __seterrno (); return -1; } gid = cygsid (group_sid).get_gid (); __aclent16_t lacl[MAX_ACL_ENTRIES]; memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (__aclent16_t)); lacl[0].a_type = USER_OBJ; lacl[0].a_id = uid; lacl[1].a_type = GROUP_OBJ; lacl[1].a_id = gid; lacl[2].a_type = OTHER_OBJ; lacl[2].a_id = ILLEGAL_GID; lacl[3].a_type = CLASS_OBJ; lacl[3].a_id = ILLEGAL_GID; lacl[3].a_perm = S_IROTH | S_IWOTH | S_IXOTH; PACL acl; BOOL acl_exists; if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) { __seterrno (); debug_printf ("GetSecurityDescriptorDacl %E"); return -1; } int pos, i, types_def = 0; if (!acl_exists || !acl) for (pos = 0; pos < 3; ++pos) /* Don't change CLASS_OBJ entry */ lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH; else { for (i = 0; i < acl->AceCount; ++i) { ACCESS_ALLOWED_ACE *ace; if (!GetAce (acl, i, (PVOID *) &ace)) continue; cygsid ace_sid ((PSID) &ace->SidStart); int id; int type = 0; if (ace_sid == well_known_world_sid) { type = OTHER_OBJ; id = ILLEGAL_GID; } else if (ace_sid == group_sid) { type = GROUP_OBJ; id = gid; } else if (ace_sid == owner_sid) { type = USER_OBJ; id = uid; } else { id = ace_sid.get_id (FALSE, &type); if (type != GROUP) { int type2 = 0; int id2 = ace_sid.get_id (TRUE, &type2); if (type2 == GROUP) { id = id2; type = GROUP; } } } if (!type) continue; if (!(ace->Header.AceFlags & INHERIT_ONLY)) { if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); } if ((ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT) && (attr & FILE_ATTRIBUTE_DIRECTORY)) { type |= ACL_DEFAULT; types_def |= type; if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); } } /* Include DEF_CLASS_OBJ if any default ace exists */ if ((types_def & (USER|GROUP)) && ((pos = searchace (lacl, MAX_ACL_ENTRIES, DEF_CLASS_OBJ)) >= 0)) { lacl[pos].a_type = DEF_CLASS_OBJ; lacl[pos].a_id = ILLEGAL_GID; lacl[pos].a_perm = S_IRWXU | S_IRWXG | S_IRWXO; } } if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) pos = MAX_ACL_ENTRIES; if (aclbufp) { if (EqualSid (owner_sid, group_sid)) lacl[0].a_perm = lacl[1].a_perm; if (pos > nentries) { set_errno (ENOSPC); return -1; } memcpy (aclbufp, lacl, pos * sizeof (__aclent16_t)); for (i = 0; i < pos; ++i) aclbufp[i].a_perm &= ~(DENY_R | DENY_W | DENY_X); aclsort (pos, 0, aclbufp); } syscall_printf ("%d = getacl (%s)", pos, file); return pos;}intacl_access (const char *path, int flags){ __aclent16_t acls[MAX_ACL_ENTRIES]; int cnt; if ((cnt = acl (path, GETACL, MAX_ACL_ENTRIES, acls)) < 1) return -1; /* Only check existance. */ if (!(flags & (R_OK | W_OK | X_OK))) return 0; for (int i = 0; i < cnt; ++i) { switch (acls[i].a_type) { case USER_OBJ: case USER: if (acls[i].a_id != myself->uid) { /* * Check if user is a NT group: * Take SID from passwd, search SID in group, check is_grp_member. */ cygsid owner; cygsid group; struct passwd *pw; struct __group32 *gr = NULL; if ((pw = getpwuid32 (acls[i].a_id)) != NULL && owner.getfrompw (pw)) { for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) if (group.getfromgr (gr) && owner == group && is_grp_member (myself->uid, gr->gr_gid)) break; } if (!gr) continue; } break; case GROUP_OBJ: case GROUP: if (acls[i].a_id != myself->gid && !is_grp_member (myself->uid, acls[i].a_id)) continue; break; case OTHER_OBJ: break; default: continue; } if ((!(flags & R_OK) || (acls[i].a_perm & S_IROTH)) && (!(flags & W_OK) || (acls[i].a_perm & S_IWOTH)) && (!(flags & X_OK) || (acls[i].a_perm & S_IXOTH))) return 0; } set_errno (EACCES); return -1;}staticintacl_worker (const char *path, int cmd, int nentries, __aclent16_t *aclbufp, int nofollow){ extern suffix_info stat_suffixes[]; path_conv real_path (path, (nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) | PC_FULL, stat_suffixes); if (real_path.error) { set_errno (real_path.error); syscall_printf ("-1 = acl (%s)", path); return -1; } if (!real_path.has_acls () || !allow_ntsec) { struct __stat64 st; int ret = -1; switch (cmd) { case SETACL: set_errno (ENOSYS); break; case GETACL: if (nentries < 1) set_errno (EINVAL); else if ((nofollow && !lstat64 (path, &st)) || (!nofollow && !stat64 (path, &st))) { __aclent16_t lacl[4]; if (nentries > 0) { lacl[0].a_type = USER_OBJ; lacl[0].a_id = st.st_uid; lacl[0].a_perm = (st.st_mode & S_IRWXU) >> 6; } if (nentries > 1) { lacl[1].a_type = GROUP_OBJ; lacl[1].a_id = st.st_gid; lacl[1].a_perm = (st.st_mode & S_IRWXG) >> 3; } if (nentries > 2) { lacl[2].a_type = OTHER_OBJ; lacl[2].a_id = ILLEGAL_GID; lacl[2].a_perm = st.st_mode & S_IRWXO; } if (nentries > 3) { lacl[3].a_type = CLASS_OBJ; lacl[3].a_id = ILLEGAL_GID; lacl[3].a_perm = S_IRWXU | S_IRWXG | S_IRWXO; } if (nentries > 4) nentries = 4; if (aclbufp) memcpy (aclbufp, lacl, nentries * sizeof (__aclent16_t)); ret = nentries; } break; case GETACLCNT:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -