Index: configure =================================================================== RCS file: /src/cvsroot/winsup-000106/configure,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 configure --- configure 2000/01/07 22:48:56 1.1.1.1 +++ configure 2000/01/08 18:23:56 @@ -642,7 +642,7 @@ test "$host_alias" != "$target_alias" && program_prefix=${target_alias}- -SUBDIRS="cygwin w32api mingw utils doc" +SUBDIRS="cygwin w32api mingw mingw/profile utils doc" subdirs="$SUBDIRS" echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 Index: cygwin/cygwin.din =================================================================== RCS file: /src/cvsroot/winsup-000106/cygwin/cygwin.din,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 cygwin.din --- cygwin/cygwin.din 2000/01/07 22:48:57 1.1.1.1 +++ cygwin/cygwin.din 2000/01/07 23:01:08 @@ -1029,3 +1029,23 @@ cygwin32_internal = cygwin_internal @PTH_ALLOW@sem_wait @PTH_ALLOW@sem_trywait @PTH_ALLOW@sem_post +acl +_acl = acl +facl +_facl = facl +aclcheck +_aclcheck = aclcheck +aclsort +_aclsort = aclsort +acltomode +_acltomode = acltomode +aclfrommode +_aclfrommode = aclfrommode +acltopbits +_acltopbits = acltopbits +aclfrompbits +_aclfrompbits = aclfrompbits +acltotext +_acltotext = acltotext +aclfromtext +_aclfromtext = aclfromtext Index: cygwin/grp.cc =================================================================== RCS file: /src/cvsroot/winsup-000106/cygwin/grp.cc,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 grp.cc --- cygwin/grp.cc 2000/01/07 22:48:59 1.1.1.1 +++ cygwin/grp.cc 2000/01/07 23:01:08 @@ -230,25 +230,16 @@ setgrent () grp_pos = 0; } -/* Cygwin doesn't support supplementary groups so we - return only the current gid */ -extern "C" int -getgroups (int gidsetsize, gid_t *grouplist) +getgroups (int gidsetsize, gid_t *grouplist, gid_t gid, const char *username) { -#if 0 - if (gidsetsize <= 0) - return 0; - grouplist[0] = myself->gid; - return 1; -#else if (!group_in_memory_p) read_etc_group(); int cnt = 0; for (int i = 0; i < curr_lines; ++i) - if (myself->gid == group_buf[i].gr_gid) + if (gid == group_buf[i].gr_gid) { if (cnt < gidsetsize) grouplist[cnt] = group_buf[i].gr_gid; @@ -258,7 +249,7 @@ getgroups (int gidsetsize, gid_t *groupl } else if (group_buf[i].gr_mem) for (int gi = 0; group_buf[i].gr_mem[gi]; ++gi) - if (! strcasecmp (myself->username, group_buf[i].gr_mem[gi])) + if (! strcasecmp (username, group_buf[i].gr_mem[gi])) { if (cnt < gidsetsize) grouplist[cnt] = group_buf[i].gr_gid; @@ -268,6 +259,19 @@ getgroups (int gidsetsize, gid_t *groupl } out: return cnt; +} + +extern "C" +int +getgroups (int gidsetsize, gid_t *grouplist) +{ +#if 0 + if (gidsetsize <= 0) + return 0; + grouplist[0] = myself->gid; + return 1; +#else + return getgroups (gidsetsize, grouplist, myself->gid, myself->username); #endif } Index: cygwin/security.cc =================================================================== RCS file: /src/cvsroot/winsup-000106/cygwin/security.cc,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 security.cc --- cygwin/security.cc 2000/01/07 22:49:00 1.1.1.1 +++ cygwin/security.cc 2000/01/08 18:02:56 @@ -16,10 +16,15 @@ details. */ #include #include #include +#include #include #include +#include #include "winsup.h" +#include +#define MAX_SID_LEN 40 + extern BOOL allow_ntea; BOOL allow_ntsec = FALSE; @@ -32,6 +37,10 @@ SID_IDENTIFIER_AUTHORITY sid_auth[] = { {SECURITY_NT_AUTHORITY} }; +#define DONT_INHERIT (0) +#define INHERIT_ALL (CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) +#define INHERIT_ONLY (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) + PSID get_sid (PSID psid, DWORD s, DWORD cnt, DWORD *r) { @@ -88,7 +97,7 @@ get_gr_sid (PSID sid, struct group *gr) PSID get_admin_sid () { - static NO_COPY char admin_sid_buf[40]; + static NO_COPY char admin_sid_buf[MAX_SID_LEN]; static NO_COPY PSID admin_sid = NULL; if (!admin_sid) @@ -102,7 +111,7 @@ get_admin_sid () PSID get_system_sid () { - static NO_COPY char system_sid_buf[40]; + static NO_COPY char system_sid_buf[MAX_SID_LEN]; static NO_COPY PSID system_sid = NULL; if (!system_sid) @@ -116,7 +125,7 @@ get_system_sid () PSID get_creator_owner_sid () { - static NO_COPY char owner_sid_buf[40]; + static NO_COPY char owner_sid_buf[MAX_SID_LEN]; static NO_COPY PSID owner_sid = NULL; if (!owner_sid) @@ -130,7 +139,7 @@ get_creator_owner_sid () PSID get_world_sid () { - static NO_COPY char world_sid_buf[40]; + static NO_COPY char world_sid_buf[MAX_SID_LEN]; static NO_COPY PSID world_sid = NULL; if (!world_sid) @@ -144,8 +153,8 @@ get_world_sid () int passwd_sem = 0; int group_sem = 0; -int __stdcall -get_id_from_sid (PSID psid, BOOL search_grp) +static int +get_id_from_sid (PSID psid, BOOL search_grp, int *type) { if (!IsValidSid (psid)) { @@ -157,7 +166,7 @@ get_id_from_sid (PSID psid, BOOL search_ /* First try to get SID from passwd or group entry */ if (allow_ntsec) { - char sidbuf[40]; + char sidbuf[MAX_SID_LEN]; PSID sid = (PSID) sidbuf; int id = -1; @@ -179,9 +188,13 @@ get_id_from_sid (PSID psid, BOOL search_ endpwent (); --passwd_sem; if (id >= 0) - return id; + { + if (type) + *type = USER; + return id; + } } - else + if (search_grp || type) { if (group_sem > 0) return 0; @@ -199,79 +212,113 @@ get_id_from_sid (PSID psid, BOOL search_ endgrent (); --group_sem; if (id >= 0) - return id; + { + if (type) + *type = GROUP; + return id; + } } } - /* - * FIXME: I don't know if it really works in any case, but calling - * LookupAccountSid() and NetxxxGetInfo() has very poor performance - * especially in domain environments - */ - /* It seems like the uid (or gid) is the last sub authority of the sid */ + /* We use the RID as default UID/GID */ int id = *GetSidSubAuthority(psid, *GetSidSubAuthorityCount(psid) - 1); - if ((WORD) id == (WORD) -1) + /* + * The RID maybe -1 if accountname == computername. + * In this case we search for the accountname in the passwd and group files. + * If type is needed, we search in each case. + */ + if (id == -1 || type) { - /* - * the last subauthority is sometimes -1, we have to go the - * 'clean way' in this case - */ - - char account[100]; - char domain[100]; - DWORD account_length = 100; - DWORD domain_length = 100; - SID_NAME_USE account_type; + char account[MAX_USER_NAME]; + char domain[MAX_COMPUTERNAME_LENGTH+1]; + DWORD acc_len = MAX_USER_NAME; + DWORD dom_len = MAX_COMPUTERNAME_LENGTH+1; + SID_NAME_USE acc_type; - if (!LookupAccountSid (NULL, psid, account, &account_length, - domain, &domain_length, &account_type)) + if (!LookupAccountSid (NULL, psid, account, &acc_len, + domain, &dom_len, &acc_type)) { __seterrno (); return -1; } - switch (account_type) + switch (acc_type) { - case SidTypeUser: - { - struct passwd *pw = getpwnam (account); - return pw ? pw->pw_uid : getuid (); - } case SidTypeGroup: - { - struct group *gr = getgrnam (account); - if (gr == NULL) - { - /* local groups are more like users than like groups */ - struct passwd *pw = getpwnam (account); - return pw ? pw->pw_uid : getuid (); - } - return gr->gr_gid; - } + case SidTypeAlias: + case SidTypeWellKnownGroup: + if (type) + *type = GROUP; + if (id == -1) + { + struct group *gr = getgrnam (account); + if (gr) + id = gr->gr_gid; + } + break; + case SidTypeUser: + if (type) + *type = USER; + if (id == -1) + { + struct passwd *pw = getpwnam (account); + if (pw) + id = pw->pw_uid; + } + break; default: - return getuid (); + break; } } - + if (id == -1) + id = getuid (); return id; } +int +get_id_from_sid (PSID psid, BOOL search_grp) +{ + return get_id_from_sid (psid, search_grp, NULL); +} + static BOOL legal_sid_type (SID_NAME_USE type) { return type == SidTypeUser || type == SidTypeGroup || SidTypeAlias || SidTypeWellKnownGroup; } + +BOOL +is_grp_member (uid_t uid, gid_t gid) +{ + extern int getgroups (int, gid_t *, gid_t, const char *); + BOOL grp_member = TRUE; + + if (!group_sem && !passwd_sem) + { + struct passwd *pw = getpwuid (uid); + gid_t grps[NGROUPS_MAX]; + int cnt = getgroups (NGROUPS_MAX, grps, + pw ? pw->pw_gid : myself->gid, + pw ? pw->pw_name : myself->username); + int i; + for (i = 0; i < cnt; ++i) + if (grps[i] == gid) + break; + grp_member = (i < cnt); + } + return grp_member; +} -BOOL __stdcall +BOOL lookup_name (const char *name, const char *logsrv, PSID ret_sid) { - char sidbuf[40]; + char sidbuf[MAX_SID_LEN]; PSID sid = (PSID) sidbuf; DWORD sidlen; - char domuser[356]; - char dom[100]; + char domuser[MAX_COMPUTERNAME_LENGTH+MAX_USER_NAME+1]; + char dom[MAX_COMPUTERNAME_LENGTH+1]; DWORD domlen; SID_NAME_USE acc_type; @@ -283,8 +330,8 @@ lookup_name (const char *name, const cha if (logsrv && *logsrv) { if (LookupAccountName (logsrv, name, - sid, (sidlen = 40, &sidlen), - dom, (domlen = 100, &domlen), + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), &acc_type) && legal_sid_type (acc_type)) goto got_it; @@ -292,14 +339,14 @@ lookup_name (const char *name, const cha { strcat (strcat (strcpy (domuser, dom), "\\"), name); if (LookupAccountName (logsrv, domuser, - sid, (sidlen = 40, &sidlen), - dom, (domlen = 100, &domlen), + sid,(sidlen = MAX_SID_LEN, &sidlen), + dom,(domlen = MAX_COMPUTERNAME_LENGTH,&domlen), &acc_type)) goto got_it; } } if (LookupAccountName (NULL, name, - sid, (sidlen = 40, &sidlen), + sid, (sidlen = MAX_SID_LEN, &sidlen), dom, (domlen = 100, &domlen), &acc_type) && legal_sid_type (acc_type)) @@ -308,8 +355,8 @@ lookup_name (const char *name, const cha { strcat (strcat (strcpy (domuser, dom), "\\"), name); if (LookupAccountName (NULL, domuser, - sid, (sidlen = 40, &sidlen), - dom, (domlen = 100, &domlen), + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), &acc_type)) goto got_it; } @@ -563,10 +610,10 @@ get_nt_attribute (const char *file, int /* Yeah, sounds too much, but I've seen SDs of 2100 bytes! */ DWORD sd_size = 4096; char sd_buf[4096]; - PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) sd_buf; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; int ret; - if ((ret = ReadSD (file, sd, &sd_size)) <= 0) + if ((ret = ReadSD (file, psd, &sd_size)) <= 0) { debug_printf ("ReadSD %E"); return ret; @@ -576,29 +623,15 @@ get_nt_attribute (const char *file, int PSID group_sid; BOOL dummy; - if (! GetSecurityDescriptorOwner (sd, &owner_sid, &dummy)) + if (! GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) debug_printf ("GetSecurityDescriptorOwner %E"); - if (! GetSecurityDescriptorGroup (sd, &group_sid, &dummy)) + if (! GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) debug_printf ("GetSecurityDescriptorGroup %E"); -// DEBUG - SECURITY_DESCRIPTOR_CONTROL sdc; - DWORD rev; - - if (GetSecurityDescriptorControl (sd, &sdc, &rev)) - { - debug_printf ("SE_DACL_AUTO_INHERITED: %d", - (sdc & SE_DACL_AUTO_INHERITED) != 0); - debug_printf ("SE_DACL_PROTECTED: %d", - (sdc & SE_DACL_PROTECTED) != 0); - - } -// END DEBUG - PACL acl; BOOL acl_exists; - if (! GetSecurityDescriptorDacl (sd, &acl_exists, &acl, &dummy)) + if (! GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) { __seterrno (); debug_printf ("GetSecurityDescriptorDacl %E"); @@ -612,73 +645,88 @@ get_nt_attribute (const char *file, int return 0; } - BOOL has_owner_bits = FALSE; - BOOL has_group_bits = FALSE; - BOOL has_world_bits = FALSE; + BOOL grp_member = is_grp_member (get_uid_from_sid (owner_sid), + get_gid_from_sid (group_sid)); + ACCESS_ALLOWED_ACE *ace; + int allow = 0; + int deny = 0; + int *flags, *anti; + for (DWORD i = 0; i < acl->AceCount; ++i) { - ACCESS_ALLOWED_ACE *ace; + if (!GetAce (acl, i, (PVOID *) &ace)) + continue; + if (ace->Header.AceFlags & INHERIT_ONLY_ACE) + continue; + switch (ace->Header.AceType) + { + case ACCESS_ALLOWED_ACE_TYPE: + flags = &allow; + anti = &deny; + break; + case ACCESS_DENIED_ACE_TYPE: + flags = &deny; + anti = &allow; + break; + default: + continue; + } - if (GetAce (acl, i, (PVOID *) &ace)) - { - switch (ace->Header.AceType) - { - case ACCESS_ALLOWED_ACE_TYPE: - if (owner_sid && EqualSid ((PSID) &ace->SidStart, owner_sid)) - { - *attribute &= ~S_IRWXU; - has_owner_bits = TRUE; - if (ace->Mask & FILE_READ_DATA) - *attribute |= S_IRUSR; - if (ace->Mask & FILE_WRITE_DATA) - *attribute |= S_IWUSR; - if (ace->Mask & FILE_EXECUTE) - *attribute |= S_IXUSR; - } - else if (group_sid && EqualSid ((PSID) &ace->SidStart, group_sid)) - { - *attribute &= ~S_IRWXG; - has_group_bits = TRUE; - if (ace->Mask & FILE_READ_DATA) - *attribute |= S_IRGRP; - if (ace->Mask & FILE_WRITE_DATA) - *attribute |= S_IWGRP; - if (ace->Mask & FILE_EXECUTE) - *attribute |= S_IXGRP; - } - else if (EqualSid ((PSID) &ace->SidStart, get_world_sid ())) - { - *attribute &= ~S_IRWXO; - has_world_bits = TRUE; - if (ace->Mask & FILE_READ_DATA) - *attribute |= S_IROTH; - if (ace->Mask & FILE_WRITE_DATA) - *attribute |= S_IWOTH; - if (ace->Mask & FILE_EXECUTE) - { - *attribute |= S_IXOTH; - // Sticky bit for directories according to linux rules. - // No sense for files. - if (! (ace->Mask & FILE_DELETE_CHILD) && - S_ISDIR(*attribute)) - *attribute |= S_ISVTX; - } - } - break; - case ACCESS_DENIED_ACE_TYPE: - // Still ignored! - break; - default: - break; - } - } + PSID ace_sid = (PSID) &ace->SidStart; + if (owner_sid && EqualSid (ace_sid, owner_sid)) + { + if (ace->Mask & FILE_READ_DATA) + *flags |= S_IRUSR; + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_IWUSR; + if (ace->Mask & FILE_EXECUTE) + *flags |= S_IXUSR; + } + else if (group_sid && EqualSid (ace_sid, group_sid)) + { + if (ace->Mask & FILE_READ_DATA) + *flags |= S_IRGRP + | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0); + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_IWGRP + | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0); + if (ace->Mask & FILE_EXECUTE) + *flags |= S_IXGRP + | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0); + } + else if (EqualSid (ace_sid, get_world_sid ())) + { + if (ace->Mask & FILE_READ_DATA) + *flags |= S_IROTH + | ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) + | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_IWOTH + | ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) + | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); + if (ace->Mask & FILE_EXECUTE) + { + *flags |= S_IXOTH + | ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) + | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); + // Sticky bit for directories according to linux rules. + // No sense for files. + if (! (ace->Mask & FILE_DELETE_CHILD) + && S_ISDIR(*attribute) + && !(*anti & S_ISVTX)) + *flags |= S_ISVTX; + } + } } + *attribute &= ~(S_IRWXU|S_IRWXG|S_IRWXO|S_ISVTX); + *attribute |= allow; + *attribute &= ~deny; syscall_printf ("file: %s %x", file, *attribute); return 0; } -int __stdcall +int get_file_attribute (int use_ntsec, const char *file, int *attribute) { if (!attribute) @@ -708,10 +756,44 @@ get_file_attribute (int use_ntsec, const return -1; } +BOOL add_access_allowed_ace (PACL acl, int offset, DWORD attributes, + PSID sid, size_t &len_add, DWORD inherit) +{ + if (! AddAccessAllowedAce (acl, ACL_REVISION, attributes, sid)) + { + __seterrno (); + return FALSE; + } + ACCESS_ALLOWED_ACE *ace; + if (GetAce(acl, offset, (PVOID *) &ace)) + ace->Header.AceFlags |= inherit; + len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + + GetLengthSid (sid); + return TRUE; +} + +BOOL add_access_denied_ace (PACL acl, int offset, DWORD attributes, + PSID sid, size_t &len_add, DWORD inherit) +{ + if (! AddAccessDeniedAce (acl, ACL_REVISION, attributes, sid)) + { + __seterrno (); + return FALSE; + } + ACCESS_DENIED_ACE *ace; + if (GetAce(acl, offset, (PVOID *) &ace)) + ace->Header.AceFlags |= inherit; + len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + + GetLengthSid (sid); + return TRUE; +} + PSECURITY_DESCRIPTOR alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute, PSECURITY_DESCRIPTOR sd_ret, DWORD *sd_size_ret) { + BOOL dummy; + if (os_being_run != winNT) return NULL; @@ -721,178 +803,210 @@ alloc_sd (uid_t uid, gid_t gid, const ch return NULL; } - char user[256]; - char *owner_sid_buf[40]; // SIDs are max 40 bytes long + // Get SID and name of new owner + char owner[MAX_USER_NAME]; + char *owner_sid_buf[MAX_SID_LEN]; PSID owner_sid = NULL; - char *group_sid_buf[40]; // SIDs are max 40 bytes long - PSID group_sid = NULL; - - SECURITY_DESCRIPTOR sd; - PSECURITY_DESCRIPTOR psd = NULL; - DWORD sd_size = 0; - - memset (&sd, 0, sizeof (sd)); - - size_t acl_len; - char acl_buf[256]; - PACL acl = (PACL) acl_buf; - struct passwd *pw = getpwuid (uid); - strcpy (user, pw ? pw->pw_name : getlogin ()); - struct group *grp = getgrgid (gid); - + strcpy (owner, pw ? pw->pw_name : getlogin ()); owner_sid = (PSID) owner_sid_buf; if ((! pw || ! get_pw_sid (owner_sid, pw)) - && ! lookup_name (user, logsrv, owner_sid)) - goto done; - - debug_printf ("user: %s [%d]", user, + && ! lookup_name (owner, logsrv, owner_sid)) + return NULL; + debug_printf ("owner: %s [%d]", owner, *GetSidSubAuthority((PSID) owner_sid, *GetSidSubAuthorityCount((PSID) owner_sid) - 1)); + // Get SID and name of new group + char *group_sid_buf[MAX_SID_LEN]; + PSID group_sid = NULL; + struct group *grp = getgrgid (gid); if (grp) { group_sid = (PSID) group_sid_buf; if ((! grp || ! get_gr_sid (group_sid, grp)) && ! lookup_name (grp->gr_name, logsrv, group_sid)) - goto done; + return NULL; } else debug_printf ("no group"); + // Initialize local security descriptor + SECURITY_DESCRIPTOR sd; + PSECURITY_DESCRIPTOR psd = NULL; if (! InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) - debug_printf ("InitializeSecurityDescriptor %E"); + { + __seterrno (); + return NULL; + } + if (! SetSecurityDescriptorOwner(&sd, owner_sid, FALSE)) { __seterrno (); - goto done; + return NULL; } if (group_sid && ! SetSecurityDescriptorGroup(&sd, group_sid, FALSE)) { __seterrno (); - goto done; + return NULL; } - - acl_len = sizeof (ACL); - - acl_len += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) - + GetLengthSid (owner_sid); - - if (! group_sid || ! EqualSid (group_sid, get_admin_sid ())) - acl_len += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) - + GetLengthSid (get_admin_sid ()); - - if (group_sid && ((attribute & S_IRWXG) - || EqualSid (group_sid, get_admin_sid ()))) - acl_len += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) - + GetLengthSid (group_sid); - if (attribute & S_IRWXO) - acl_len += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) - + GetLengthSid (get_world_sid ()); - - debug_printf ("ACL-Size: %d", acl_len); - - if (! InitializeAcl (acl, acl_len, ACL_REVISION)) - debug_printf ("InitializeAcl %E"); - - if (attribute != -1) + // Initialize local access control list + char acl_buf[3072]; + PACL acl = (PACL) acl_buf; + if (! InitializeAcl (acl, 3072, ACL_REVISION)) { - int ace_off = 0; - ACCESS_ALLOWED_ACE *ace; - - DWORD access = STANDARD_RIGHTS_ALL; - - /* - * VTX bit may only be set if executable for `other' is set. - * For correct handling under WinNT, FILE_DELETE_CHILD has to - * be (un)set in each ACE. - */ - if (! (attribute & S_IXOTH)) - attribute &= ~S_ISVTX; - - if (attribute & S_IRUSR) - access |= FILE_GENERIC_READ | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA; - if (attribute & S_IWUSR) - access |= FILE_GENERIC_WRITE | DELETE; - if (attribute & S_IXUSR) - access |= FILE_GENERIC_EXECUTE; - if (! (attribute & S_ISVTX)) - access |= FILE_DELETE_CHILD; - if (! AddAccessAllowedAce (acl, ACL_REVISION, access, owner_sid)) - debug_printf ("AddAccessAllowedAce(owner) %E"); - if (GetAce(acl, 0, (PVOID *) &ace)) - ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + __seterrno (); + return NULL; + } - if (! EqualSid (owner_sid, get_admin_sid ()) - && (! group_sid || ! EqualSid (group_sid, get_admin_sid ()))) - { - if (! AddAccessAllowedAce (acl, ACL_REVISION, - STANDARD_RIGHTS_READ | WRITE_OWNER, - get_admin_sid ())) - debug_printf ("AddAccessAllowedAce(admin) %E"); - if (GetAce(acl, 1, (PVOID *) &ace)) - ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; - ace_off = 1; - } + // VTX bit may only be set if executable for `other' is set. + // For correct handling under WinNT, FILE_DELETE_CHILD has to + // be (un)set in each ACE. + if (! (attribute & S_IXOTH)) + attribute &= ~S_ISVTX; + + // From here fill ACL + size_t acl_len = sizeof (ACL); + int ace_off = 0; + + // Construct allow attribute for owner + DWORD owner_allow = (STANDARD_RIGHTS_ALL & ~DELETE) + | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA; + if (attribute & S_IRUSR) + owner_allow |= FILE_GENERIC_READ; + if (attribute & S_IWUSR) + owner_allow |= FILE_GENERIC_WRITE | DELETE; + if (attribute & S_IXUSR) + owner_allow |= FILE_GENERIC_EXECUTE; + if (! (attribute & S_ISVTX)) + owner_allow |= FILE_DELETE_CHILD; + + // Construct allow attribute for group + DWORD group_allow = STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA; + if (attribute & S_IRGRP) + group_allow |= FILE_GENERIC_READ; + if (attribute & S_IWGRP) + group_allow |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | DELETE; + if (attribute & S_IXGRP) + group_allow |= FILE_GENERIC_EXECUTE; + if (! (attribute & S_ISVTX)) + group_allow |= FILE_DELETE_CHILD; + + // Construct allow attribute for everyone + DWORD other_allow = STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA; + if (attribute & S_IROTH) + other_allow |= FILE_GENERIC_READ; + if (attribute & S_IWOTH) + other_allow |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | DELETE; + if (attribute & S_IXOTH) + other_allow |= FILE_GENERIC_EXECUTE; + if (! (attribute & S_ISVTX)) + other_allow |= FILE_DELETE_CHILD; + + // Construct deny attributes for owner and group + DWORD owner_deny = 0; + if (is_grp_member (uid, gid)) + owner_deny = ~owner_allow & (group_allow | other_allow); + else + owner_deny = ~owner_allow & other_allow; + owner_deny &= ~(STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA + | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA); + DWORD group_deny = ~group_allow & other_allow; + group_deny &= ~(STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA); + + // Set deny ACE for owner + if (owner_deny + && ! add_access_denied_ace (acl, ace_off++, owner_deny, + owner_sid, acl_len, INHERIT_ALL)) + return NULL; + // Set allow ACE for owner + if (! add_access_allowed_ace (acl, ace_off++, owner_allow, + owner_sid, acl_len, INHERIT_ALL)) + return NULL; + // Set deny ACE for group + if (group_deny + && ! add_access_denied_ace (acl, ace_off++, group_deny, + group_sid, acl_len, INHERIT_ALL)) + return NULL; + // Set allow ACE for group + if (! add_access_allowed_ace (acl, ace_off++, group_allow, + group_sid, acl_len, INHERIT_ALL)) + return NULL; + // Set allow ACE for everyone + if (! add_access_allowed_ace (acl, ace_off++, other_allow, + get_world_sid (), acl_len, INHERIT_ALL)) + return NULL; - if (group_sid && ((attribute & S_IRWXG) - || EqualSid (group_sid, get_admin_sid ()))) - { - access = STANDARD_RIGHTS_READ; - if (EqualSid (group_sid, get_admin_sid ())) - access |= WRITE_DAC | WRITE_OWNER - | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA; - if (attribute & S_IRGRP) - access |= FILE_GENERIC_READ; - if (attribute & S_IWGRP) - access |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | DELETE; - if (attribute & S_IXGRP) - access |= FILE_GENERIC_EXECUTE; - if (! (attribute & S_ISVTX)) - access |= FILE_DELETE_CHILD; - if (! AddAccessAllowedAce (acl, ACL_REVISION, access, group_sid)) - debug_printf ("AddAccessAllowedAce(group) %E"); - if (GetAce(acl, 1 + ace_off, (PVOID *) &ace)) - ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; - } + // Get owner and group from current security descriptor + PSID cur_owner_sid = NULL; + PSID cur_group_sid = NULL; + if (! GetSecurityDescriptorOwner (sd_ret, &cur_owner_sid, &dummy)) + debug_printf ("GetSecurityDescriptorOwner %E"); + if (! GetSecurityDescriptorGroup (sd_ret, &cur_group_sid, &dummy)) + debug_printf ("GetSecurityDescriptorGroup %E"); - if (attribute & S_IRWXO) + // Fill ACL with unrelated ACEs from current security descriptor + PACL oacl; + BOOL acl_exists; + ACCESS_ALLOWED_ACE *ace; + if (GetSecurityDescriptorDacl (sd_ret, &acl_exists, &oacl, &dummy) + && acl_exists && oacl) + for (DWORD i = 0; i < oacl->AceCount; ++i) + if (GetAce (oacl, i, (PVOID *) &ace)) { - access = STANDARD_RIGHTS_READ; - if (attribute & S_IROTH) - access |= FILE_GENERIC_READ; - if (attribute & S_IWOTH) - access |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | DELETE; - if (attribute & S_IXOTH) - access |= FILE_GENERIC_EXECUTE; - if (! (attribute & S_ISVTX)) - access |= FILE_DELETE_CHILD; - - if (! AddAccessAllowedAce (acl, ACL_REVISION, access, get_world_sid ())) - debug_printf ("AddAccessAllowedAce(world) %E"); - if (GetAce(acl, 2 + ace_off, (PVOID *) &ace)) - ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + PSID ace_sid = (PSID) &ace->SidStart; + // Check for related ACEs + if ((cur_owner_sid && EqualSid (ace_sid, cur_owner_sid)) + || (owner_sid && EqualSid (ace_sid, owner_sid)) + || (cur_group_sid && EqualSid (ace_sid, cur_group_sid)) + || (group_sid && EqualSid (ace_sid, group_sid)) + || (EqualSid (ace_sid, get_world_sid ()))) + continue; + // Add unrelated ACE + if (! AddAce(acl, ACL_REVISION, + ace->Header.AceType == ACCESS_DENIED_ACE_TYPE ? + 0 : MAXDWORD, + (LPVOID) ace, ace->Header.AceSize)) + { + __seterrno (); + return NULL; + } + acl_len += ace->Header.AceSize; + ++ace_off; } - if (! SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) - debug_printf ("SetSecurityDescriptorDacl %E"); - } + // Set AclSize to computed value + acl->AclSize = acl_len; + debug_printf ("ACL-Size: %d", acl_len); - sd_size = *sd_size_ret; + // Create DACL for local security descriptor + if (! SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) + { + __seterrno (); + return NULL; + } - memset (sd_ret, 0, sd_size); - if (! MakeSelfRelativeSD (&sd, sd_ret, &sd_size)) + // Make self relative security descriptor + *sd_size_ret = 0; + MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret); + if (*sd_size_ret <= 0) { __seterrno (); - goto done; + return NULL; } + if (! MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret)) + { + __seterrno (); + return NULL; + } psd = sd_ret; debug_printf ("Created SD-Size: %d", *sd_size_ret); -done: - *sd_size_ret = sd_size; return psd; } @@ -906,19 +1020,25 @@ set_nt_attribute (const char *file, uid_ if (set_process_privileges () < 0) return -1; - DWORD sd_size = 512; - char sd_buf[512]; + DWORD sd_size = 4096; + char sd_buf[4096]; PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + int ret; + if ((ret = ReadSD (file, psd, &sd_size)) <= 0) + { + debug_printf ("ReadSD %E"); + return ret; + } + + sd_size = 4096; if (! (psd = alloc_sd (uid, gid, logsrv, attribute, psd, &sd_size))) return -1; - - int ret = WriteSD (file, psd, sd_size); - return ret; + return WriteSD (file, psd, sd_size); } -int __stdcall +int set_file_attribute (int use_ntsec, const char *file, uid_t uid, gid_t gid, int attribute, const char *logsrv) @@ -945,11 +1065,951 @@ set_file_attribute (int use_ntsec, const return ret2; } -int __stdcall +int set_file_attribute (int use_ntsec, const char *file, int attribute) { return set_file_attribute (use_ntsec, file, myself->uid, myself->gid, attribute, myself->logsrv); +} + +static int +setacl (const char *file, int nentries, const aclent_t *aclbufp) +{ + DWORD sd_size = 4096; + char sd_buf[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + + if (ReadSD (file, psd, &sd_size) <= 0) + { + debug_printf ("ReadSD %E"); + return -1; + } + + BOOL dummy; + + // Get owner SID + PSID owner_sid = NULL; + if (! GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) + { + __seterrno (); + return -1; + } + char owner_buf[MAX_SID_LEN]; + if (!CopySid (MAX_SID_LEN, (PSID) owner_buf, owner_sid)) + { + __seterrno (); + return -1; + } + owner_sid = (PSID) owner_buf; + + // Get group SID + PSID group_sid = NULL; + if (! GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) + { + __seterrno (); + return -1; + } + char group_buf[MAX_SID_LEN]; + if (!CopySid (MAX_SID_LEN, (PSID) group_buf, group_sid)) + { + __seterrno (); + return -1; + } + group_sid = (PSID) group_buf; + + // Initialize local security descriptor + SECURITY_DESCRIPTOR sd; + if (! InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) + { + __seterrno (); + return -1; + } + if (! SetSecurityDescriptorOwner(&sd, owner_sid, FALSE)) + { + __seterrno (); + return -1; + } + if (group_sid + && ! SetSecurityDescriptorGroup(&sd, group_sid, 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; + + char sidbuf[MAX_SID_LEN]; + PSID sid = (PSID) sidbuf; + struct passwd *pw; + struct group *gr; + + 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 + | DELETE | FILE_DELETE_CHILD; + if (aclbufp[i].a_perm & S_IXOTH) + allow |= FILE_GENERIC_EXECUTE; + switch (aclbufp[i].a_type) + { + case USER_OBJ: + allow |= STANDARD_RIGHTS_ALL & ~DELETE; + if (! add_access_allowed_ace (acl, ace_off++, allow, + owner_sid, acl_len, DONT_INHERIT)) + return -1; + break; + case USER: + if (!(pw = getpwuid (aclbufp[i].a_id)) + || ! get_pw_sid (sid, pw) + || ! add_access_allowed_ace (acl, ace_off++, allow, + sid, acl_len, DONT_INHERIT)) + return -1; + break; + case GROUP_OBJ: + if (! add_access_allowed_ace (acl, ace_off++, allow, + group_sid, acl_len, DONT_INHERIT)) + return -1; + break; + case GROUP: + if (!(gr = getgrgid (aclbufp[i].a_id)) + || ! get_gr_sid (sid, gr) + || ! add_access_allowed_ace (acl, ace_off++, allow, + sid, acl_len, DONT_INHERIT)) + return -1; + break; + case OTHER_OBJ: + if (! add_access_allowed_ace (acl, ace_off++, allow, + get_world_sid(), acl_len, DONT_INHERIT)) + return -1; + break; + case DEF_USER_OBJ: + allow |= STANDARD_RIGHTS_ALL & ~DELETE; + if (! add_access_allowed_ace (acl, ace_off++, allow, + owner_sid, acl_len, INHERIT_ONLY)) + return -1; + break; + case DEF_USER: + if (!(pw = getpwuid (aclbufp[i].a_id)) + || ! get_pw_sid (sid, pw) + || ! add_access_allowed_ace (acl, ace_off++, allow, + sid, acl_len, INHERIT_ONLY)) + return -1; + break; + case DEF_GROUP_OBJ: + if (! add_access_allowed_ace (acl, ace_off++, allow, + group_sid, acl_len, INHERIT_ONLY)) + return -1; + break; + case DEF_GROUP: + if (!(gr = getgrgid (aclbufp[i].a_id)) + || ! get_gr_sid (sid, gr) + || ! add_access_allowed_ace (acl, ace_off++, allow, + sid, acl_len, INHERIT_ONLY)) + return -1; + break; + case DEF_OTHER_OBJ: + if (! add_access_allowed_ace (acl, ace_off++, allow, + get_world_sid(), acl_len, INHERIT_ONLY)) + 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 WriteSD (file, psd, sd_size); +} + +static void +getace (aclent_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) + if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) + acl.a_perm |= (acl.a_perm & S_IRGRP) ? 0 : S_IRUSR; + else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) + acl.a_perm &= ~S_IRGRP; + + if (win_ace_mask & FILE_WRITE_DATA) + if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) + acl.a_perm |= (acl.a_perm & S_IWGRP) ? 0 : S_IWUSR; + else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) + acl.a_perm &= ~S_IWGRP; + + if (win_ace_mask & FILE_EXECUTE) + if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) + acl.a_perm |= (acl.a_perm & S_IXGRP) ? 0 : S_IXUSR; + else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) + acl.a_perm &= ~S_IXGRP; +} + +static int +searchace (aclent_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 int +getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp) +{ + DWORD sd_size = 4096; + char sd_buf[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + + int ret; + if ((ret = ReadSD (file, psd, &sd_size)) <= 0) + { + debug_printf ("ReadSD %E"); + return ret; + } + + PSID owner_sid; + PSID group_sid; + BOOL dummy; + uid_t uid; + gid_t gid; + + if (! GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) + { + debug_printf ("GetSecurityDescriptorOwner %E"); + __seterrno (); + return -1; + } + uid = get_uid_from_sid (owner_sid); + + if (! GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) + { + debug_printf ("GetSecurityDescriptorGroup %E"); + __seterrno (); + return -1; + } + gid = get_gid_from_sid (group_sid); + + aclent_t lacl[MAX_ACL_ENTRIES]; + memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_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; + + PACL acl; + BOOL acl_exists; + + if (! GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) + { + __seterrno (); + debug_printf ("GetSecurityDescriptorDacl %E"); + return -1; + } + + int pos, i; + + if (! acl_exists || ! acl) + { + for (pos = 0; pos < MIN_ACL_ENTRIES; ++pos) + lacl[pos].a_perm = S_IRWXU | S_IRWXG | S_IRWXO; + pos = nentries < MIN_ACL_ENTRIES ? nentries : MIN_ACL_ENTRIES; + memcpy (aclbufp, lacl, pos * sizeof (aclent_t)); + return pos; + } + + for (i = 0; i < acl->AceCount && (!nentries || i < nentries); ++i) + { + ACCESS_ALLOWED_ACE *ace; + + if (!GetAce (acl, i, (PVOID *) &ace)) + continue; + + PSID ace_sid = (PSID) &ace->SidStart; + int id; + int type = 0; + + if (EqualSid (ace_sid, owner_sid)) + { + type = USER_OBJ; + id = uid; + } + else if (EqualSid (ace_sid, group_sid)) + { + type = GROUP_OBJ; + id = gid; + } + else if (EqualSid (ace_sid, get_world_sid ())) + { + type = OTHER_OBJ; + id = 0; + } + else + { + id = get_id_from_sid (ace_sid, FALSE, &type); + if (type != GROUP) + { + int type2 = 0; + int id2 = get_id_from_sid (ace_sid, TRUE, &type2); + if (type2 == GROUP) + { + id = id2; + type = GROUP; + } + } + } + if (!type) + continue; + if (!(ace->Header.AceFlags & INHERIT_ONLY_ACE)) + { + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) + getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); + } + if ((ace->Header.AceFlags & INHERIT_ALL) + && (attr & FILE_ATTRIBUTE_DIRECTORY)) + { + type |= ACL_DEFAULT; + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) + getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); + } + } + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) + pos = MAX_ACL_ENTRIES; + for (i = 0; i < pos; ++i) + { + lacl[i].a_perm = (lacl[i].a_perm & S_IRWXU) + & ~((lacl[i].a_perm & S_IRWXG) << 3); + lacl[i].a_perm |= (lacl[i].a_perm & S_IRWXU) >> 3 + | (lacl[i].a_perm & S_IRWXU) >> 6; + } + if ((searchace (lacl, MAX_ACL_ENTRIES, USER) >= 0 + || searchace (lacl, MAX_ACL_ENTRIES, GROUP) >= 0) + && (pos = searchace (lacl, MAX_ACL_ENTRIES, CLASS_OBJ)) >= 0) + { + lacl[pos].a_type = CLASS_OBJ; + lacl[pos].a_perm = + lacl[searchace (lacl, MAX_ACL_ENTRIES, GROUP_OBJ)].a_perm; + } + int dgpos; + if ((searchace (lacl, MAX_ACL_ENTRIES, DEF_USER) >= 0 + || searchace (lacl, MAX_ACL_ENTRIES, DEF_GROUP) >= 0) + && (dgpos = searchace (lacl, MAX_ACL_ENTRIES, DEF_GROUP_OBJ)) >= 0 + && (pos = searchace (lacl, MAX_ACL_ENTRIES, DEF_CLASS_OBJ)) >= 0 + && (attr & FILE_ATTRIBUTE_DIRECTORY)) + { + lacl[pos].a_type = DEF_CLASS_OBJ; + lacl[pos].a_perm = lacl[dgpos].a_perm; + } + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) + pos = MAX_ACL_ENTRIES; + if (pos > nentries) + pos = nentries; + if (aclbufp) + memcpy (aclbufp, lacl, pos * sizeof (aclent_t)); + aclsort (pos, 0, aclbufp); + syscall_printf ("%d = getacl (%s)", pos, file); + return pos; +} + +extern "C" +int +acl (const char *path, int cmd, int nentries, aclent_t *aclbufp) +{ + if (set_process_privileges () < 0) + return -1; + + path_conv real_path (path); + if (real_path.error) + { + set_errno (real_path.error); + syscall_printf ("-1 = acl (%s)", path); + return -1; + } + if (!real_path.has_acls ()) + { + struct stat st; + int ret = -1; + + switch (cmd) + { + case SETACL: + set_errno (ENOSYS); + break; + case GETACL: + if (nentries < 1) + set_errno (EINVAL); + else if (! stat (path, &st)) + { + aclent_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) + | (st.st_mode & S_IRWXU) >> 3 + | (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) + | (st.st_mode & S_IRWXG) << 3 + | (st.st_mode & S_IRWXG) >> 3; + } + if (nentries > 2) + { + lacl[2].a_type = OTHER_OBJ; + lacl[2].a_id = 0; + lacl[2].a_perm = (st.st_mode & S_IRWXO) + | (st.st_mode & S_IRWXO) << 6 + | (st.st_mode & S_IRWXO) << 3; + } + if (nentries > 3) + { + lacl[3].a_type = CLASS_OBJ; + lacl[3].a_id = 0; + lacl[3].a_perm = (st.st_mode & S_IRWXG) + | (st.st_mode & S_IRWXG) << 3 + | (st.st_mode & S_IRWXG) >> 3; + } + if (nentries > 4) + nentries = 4; + if (aclbufp) + memcpy (aclbufp, lacl, nentries * sizeof (aclent_t)); + ret = nentries; + } + break; + case GETACLCNT: + ret = 4; + break; + } + syscall_printf ("%d = acl (%s)", ret, path); + return ret; + } + switch (cmd) + { + case SETACL: + if (!aclsort(nentries, 0, aclbufp)) + return setacl (real_path.get_win32 (), + nentries, aclbufp); + break; + case GETACL: + if (nentries < 1) + break; + return getacl (real_path.get_win32 (), + real_path.file_attributes (), + nentries, aclbufp); + case GETACLCNT: + return getacl (real_path.get_win32 (), + real_path.file_attributes (), + 0, NULL); + default: + break; + } + set_errno (EINVAL); + syscall_printf ("-1 = acl (%s)", path); + return -1; +} + +extern "C" +int +facl (int fd, int cmd, int nentries, aclent_t *aclbufp) +{ + if (dtable.not_open (fd)) + { + syscall_printf ("-1 = facl (%d)", fd); + set_errno (EBADF); + return -1; + } + const char *path = dtable[fd]->get_name (); + if (path == NULL) + { + syscall_printf ("-1 = facl (%d) (no name)", fd); + set_errno (ENOSYS); + return -1; + } + syscall_printf ("facl (%d): calling acl (%s)", fd, path); + return acl (path, cmd, nentries, aclbufp); +} + +extern "C" +int +aclcheck (aclent_t *aclbufp, int nentries, int *which) +{ + BOOL has_user_obj = FALSE; + BOOL has_group_obj = FALSE; + BOOL has_other_obj = FALSE; + BOOL has_class_obj = FALSE; + BOOL has_ug_objs = FALSE; + BOOL has_def_user_obj = FALSE; + BOOL has_def_group_obj = FALSE; + BOOL has_def_other_obj = FALSE; + BOOL has_def_class_obj = FALSE; + BOOL has_def_ug_objs = FALSE; + int pos2; + + for (int pos = 0; pos < nentries; ++pos) + switch (aclbufp[pos].a_type) + { + case USER_OBJ: + if (has_user_obj) + { + if (which) + *which = pos; + return USER_ERROR; + } + has_user_obj = TRUE; + break; + case GROUP_OBJ: + if (has_group_obj) + { + if (which) + *which = pos; + return GRP_ERROR; + } + has_group_obj = TRUE; + break; + case OTHER_OBJ: + if (has_other_obj) + { + if (which) + *which = pos; + return OTHER_ERROR; + } + has_other_obj = TRUE; + break; + case CLASS_OBJ: + if (has_class_obj) + { + if (which) + *which = pos; + return CLASS_ERROR; + } + has_class_obj = TRUE; + break; + case USER: + case GROUP: + if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1, + aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0) + { + if (which) + *which = pos2; + return DUPLICATE_ERROR; + } + has_ug_objs = TRUE; + break; + case DEF_USER_OBJ: + if (has_def_user_obj) + { + if (which) + *which = pos; + return USER_ERROR; + } + has_def_user_obj = TRUE; + break; + case DEF_GROUP_OBJ: + if (has_def_group_obj) + { + if (which) + *which = pos; + return GRP_ERROR; + } + has_def_group_obj = TRUE; + break; + case DEF_OTHER_OBJ: + if (has_def_other_obj) + { + if (which) + *which = pos; + return OTHER_ERROR; + } + has_def_other_obj = TRUE; + break; + case DEF_CLASS_OBJ: + if (has_def_class_obj) + { + if (which) + *which = pos; + return CLASS_ERROR; + } + has_def_class_obj = TRUE; + break; + case DEF_USER: + case DEF_GROUP: + if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1, + aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0) + { + if (which) + *which = pos2; + return DUPLICATE_ERROR; + } + has_def_ug_objs = TRUE; + break; + default: + return ENTRY_ERROR; + } + if (!has_user_obj + || !has_group_obj + || !has_other_obj + || (has_ug_objs && !has_class_obj) + || (has_def_ug_objs && !has_def_class_obj)) + { + if (which) + *which = -1; + return MISS_ERROR; + } + return 0; +} + +extern "C" +int acecmp (const void *a1, const void *a2) +{ +#define ace(i) ((const aclent_t *) a##i) + int ret = ace(1)->a_type - ace(2)->a_type; + if (!ret) + ret = ace(1)->a_id - ace(2)->a_id; + return ret; +#undef ace +} + +extern "C" +int +aclsort (int nentries, int calclass, aclent_t *aclbufp) +{ + if (aclcheck (aclbufp, nentries, NULL)) + return -1; + if (!aclbufp || nentries < 1) + { + set_errno (EINVAL); + return -1; + } + qsort((void *) aclbufp, nentries, sizeof (aclent_t), acecmp); + return 0; +} + +extern "C" +int +acltomode (aclent_t *aclbufp, int nentries, mode_t *modep) +{ + int pos; + + if (!aclbufp || nentries < 1 || ! modep) + { + set_errno (EINVAL); + return -1; + } + *modep = 0; + if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + *modep |= aclbufp[pos].a_perm & S_IRWXU; + if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + if (searchace (aclbufp, nentries, CLASS_OBJ) < 0) + pos = searchace (aclbufp, nentries, CLASS_OBJ); + *modep |= (aclbufp[pos].a_perm & S_IRWXU) >> 3; + if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + *modep |= (aclbufp[pos].a_perm & S_IRWXU) >> 6; + return 0; +} + +extern "C" +int +aclfrommode(aclent_t *aclbufp, int nentries, mode_t *modep) +{ + int pos; + + if (!aclbufp || nentries < 1 || ! modep) + { + set_errno (EINVAL); + return -1; + } + if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + aclbufp[pos].a_perm = (*modep & S_IRWXU) + | (*modep & S_IRWXU) >> 3 + | (*modep & S_IRWXU) >> 6; + if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + if (searchace (aclbufp, nentries, CLASS_OBJ) < 0) + pos = searchace (aclbufp, nentries, CLASS_OBJ); + aclbufp[pos].a_perm = (*modep & S_IRWXG) + | (*modep & S_IRWXG) << 3 + | (*modep & S_IRWXG) >> 3; + if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + aclbufp[pos].a_perm = (*modep & S_IRWXO) + | (*modep & S_IRWXO) << 6 + | (*modep & S_IRWXO) << 3; + return 0; +} + +extern "C" +int +acltopbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp) +{ + return acltomode (aclbufp, nentries, pbitsp); +} + +extern "C" +int +aclfrompbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp) +{ + return aclfrommode (aclbufp, nentries, pbitsp); +} + +static char * +permtostr (mode_t perm) +{ + static char pbuf[4]; + + pbuf[0] = (perm & S_IREAD) ? 'r' : '-'; + pbuf[1] = (perm & S_IWRITE) ? 'w' : '-'; + pbuf[2] = (perm & S_IEXEC) ? 'x' : '-'; + pbuf[3] = '\0'; + return pbuf; +} + +extern "C" +char * +acltotext (aclent_t *aclbufp, int aclcnt) +{ + if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES + || aclcheck (aclbufp, aclcnt, NULL)) + { + set_errno (EINVAL); + return NULL; + } + char buf[32000]; + buf[0] = '\0'; + BOOL first = TRUE; + + for (int pos = 0; pos < aclcnt; ++pos) + { + if (!first) + strcat (buf, ","); + first = FALSE; + if (aclbufp[pos].a_type & ACL_DEFAULT) + strcat (buf, "default"); + switch (aclbufp[pos].a_type) + { + case USER_OBJ: + sprintf (buf + strlen (buf), "user::%s", + permtostr (aclbufp[pos].a_perm)); + break; + case USER: + sprintf (buf + strlen (buf), "user:%d:%s", + aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); + break; + case GROUP_OBJ: + sprintf (buf + strlen (buf), "group::%s", + permtostr (aclbufp[pos].a_perm)); + break; + case GROUP: + sprintf (buf + strlen (buf), "group:%d:%s", + aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); + break; + case CLASS_OBJ: + sprintf (buf + strlen (buf), "mask::%s", + permtostr (aclbufp[pos].a_perm)); + break; + case OTHER_OBJ: + sprintf (buf + strlen (buf), "other::%s", + permtostr (aclbufp[pos].a_perm)); + break; + default: + set_errno (EINVAL); + return NULL; + } + } + return strdup (buf); +} + +static mode_t +permfromstr (char *perm) +{ + mode_t mode = 0; + + if (strlen (perm) != 3) + return 01000; + if (perm[0] == 'r') + mode |= S_IRUSR | S_IRGRP | S_IROTH; + else if (perm[0] != '-') + return 01000; + if (perm[1] == 'w') + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + else if (perm[1] != '-') + return 01000; + if (perm[2] == 'x') + mode |= S_IXUSR | S_IXGRP | S_IXOTH; + else if (perm[2] != '-') + return 01000; + return mode; +} + +extern "C" +aclent_t * +aclfromtext (char *acltextp, int *aclcnt) +{ + if (!acltextp) + { + set_errno (EINVAL); + return NULL; + } + char buf[strlen (acltextp) + 1]; + aclent_t lacl[MAX_ACL_ENTRIES]; + memset (lacl, 0, sizeof lacl); + int pos = 0; + for (char *c = strtok (buf, ","); c; c = strtok (NULL, ",")) + { + if (!strncmp (c, "default", 7)) + { + lacl[pos].a_type |= ACL_DEFAULT; + c += 7; + } + if (!strncmp (c, "user:", 5)) + { + if (c[5] == ':') + lacl[pos].a_type |= USER_OBJ; + else + { + lacl[pos].a_type |= USER; + c += 5; + if (isalpha (*c)) + { + struct passwd *pw = getpwnam (c); + if (!pw) + { + set_errno (EINVAL); + return NULL; + } + lacl[pos].a_id = pw->pw_uid; + c = strchr (c, ':'); + } + else if (isdigit (*c)) + lacl[pos].a_id = strtol (c, &c, 10); + if (!c || *c != ':') + { + set_errno (EINVAL); + return NULL; + } + } + } + else if (!strncmp (c, "group:", 6)) + { + if (c[5] == ':') + lacl[pos].a_type |= GROUP_OBJ; + else + { + lacl[pos].a_type |= GROUP; + c += 5; + if (isalpha (*c)) + { + struct group *gr = getgrnam (c); + if (!gr) + { + set_errno (EINVAL); + return NULL; + } + lacl[pos].a_id = gr->gr_gid; + c = strchr (c, ':'); + } + else if (isdigit (*c)) + lacl[pos].a_id = strtol (c, &c, 10); + if (!c || *c != ':') + { + set_errno (EINVAL); + return NULL; + } + } + } + else if (!strncmp (c, "mask:", 5)) + { + if (c[5] == ':') + lacl[pos].a_type |= CLASS_OBJ; + else + { + set_errno (EINVAL); + return NULL; + } + } + else if (!strncmp (c, "other:", 6)) + { + if (c[5] == ':') + lacl[pos].a_type |= OTHER_OBJ; + else + { + set_errno (EINVAL); + return NULL; + } + } + if ((lacl[pos].a_perm = permfromstr (c)) == 01000) + { + set_errno (EINVAL); + return NULL; + } + ++pos; + } + aclent_t *aclp = (aclent_t *) malloc (pos * sizeof (aclent_t)); + if (aclp) + memcpy (aclp, lacl, pos * sizeof (aclent_t)); + return aclp; } Index: cygwin/smallprint.c =================================================================== RCS file: /src/cvsroot/winsup-000106/cygwin/smallprint.c,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 smallprint.c --- cygwin/smallprint.c 2000/01/07 22:49:01 1.1.1.1 +++ cygwin/smallprint.c 2000/01/08 18:07:37 @@ -11,7 +11,9 @@ details. */ #include #include #include +#define __INSIDE_CYGWIN__ #include +#undef __INSIDE_CYGWIN__ #include int __small_sprintf (char *dst, const char *fmt,...); Index: cygwin/syscalls.cc =================================================================== RCS file: /src/cvsroot/winsup-000106/cygwin/syscalls.cc,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 syscalls.cc --- cygwin/syscalls.cc 2000/01/07 22:49:01 1.1.1.1 +++ cygwin/syscalls.cc 2000/01/07 23:01:08 @@ -1027,64 +1027,63 @@ access (const char *fn, int flags) r = stat (fn, &st); if (r) return -1; -#if 0 - if (flags & W_OK) + // flags were incorrectly specified + if (flags & ~(F_OK|R_OK|W_OK|X_OK)) { - if (st.st_mode & S_IWRITE) - return 0; - - /* can't write to the file */ - set_errno (EACCES); + set_errno (EINVAL); return -1; } -#else + r = -1; if (flags & R_OK) { if (st.st_uid == myself->uid) { if (!(st.st_mode & S_IRUSR)) - return -1; + goto done; } else if (st.st_gid == myself->gid) { if (!(st.st_mode & S_IRGRP)) - return -1; + goto done; } else if (!(st.st_mode & S_IROTH)) - return -1; + goto done; } if (flags & W_OK) { if (st.st_uid == myself->uid) { if (!(st.st_mode & S_IWUSR)) - return -1; + goto done; } else if (st.st_gid == myself->gid) { if (!(st.st_mode & S_IWGRP)) - return -1; + goto done; } else if (!(st.st_mode & S_IWOTH)) - return -1; + goto done; } if (flags & X_OK) { if (st.st_uid == myself->uid) { if (!(st.st_mode & S_IXUSR)) - return -1; + goto done; } else if (st.st_gid == myself->gid) { if (!(st.st_mode & S_IXGRP)) - return -1; + goto done; } else if (!(st.st_mode & S_IXOTH)) - return -1; + goto done; } -#endif - return 0; + r = 0; +done: + if (r) + set_errno (EACCES); + return r; } extern "C" Index: cygwin/regexp/regexp.c =================================================================== RCS file: /src/cvsroot/winsup-000106/cygwin/regexp/regexp.c,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 regexp.c --- cygwin/regexp/regexp.c 2000/01/07 22:49:07 1.1.1.1 +++ cygwin/regexp/regexp.c 2000/01/08 18:07:44 @@ -44,7 +44,9 @@ static char *rcsid = "$Id: regexp.c,v 1. #include "regexp.h" #include +#define __INSIDE_CYGWIN__ #include +#undef __INSIDE_CYGWIN__ #include #include #include "regmagic.h" Index: mingw/profile/configure =================================================================== RCS file: /src/cvsroot/winsup-000106/mingw/profile/configure,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 configure --- mingw/profile/configure 2000/01/07 22:49:14 1.1.1.1 +++ mingw/profile/configure 2000/01/08 18:22:02 @@ -537,7 +537,7 @@ DLLTOOL=${DLLTOOL-dlltool} DLLWRAP=${DLLWRAP-dllwrap} ac_aux_dir= -for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do +for ac_dir in $srcdir $srcdir/.. $srcdir/../.. $srcdir/../../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" Index: utils/Makefile.in =================================================================== RCS file: /src/cvsroot/winsup-000106/utils/Makefile.in,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 Makefile.in --- utils/Makefile.in 2000/01/07 22:49:19 1.1.1.1 +++ utils/Makefile.in 2000/01/08 18:34:21 @@ -58,7 +58,7 @@ MINGW_LDFLAGS:=$(ALL_LDFLAGS) $(MINGW_LI PROGS:=mount$(EXEEXT) umount$(EXEEXT) ps$(EXEEXT) kill$(EXEEXT) \ mkpasswd$(EXEEXT) mkgroup$(EXEEXT) cygpath$(EXEEXT) cygcheck$(EXEEXT) \ - passwd$(EXEEXT) strace$(EXEEXT) + passwd$(EXEEXT) getfacl$(EXEEXT) setfacl$(EXEEXT) strace$(EXEEXT) WINSUP_DEPS:=$(cygwin_source)/winsup.h @@ -71,10 +71,10 @@ all: Makefile $(PROGS) strace.exe: strace.cc mingw_getopt.o $(MINGW_LDLIBS) ifdef VERBOSE - $(CC) $(MINGW_CFLAGS) -o $@ ${wordlist 1,2,$^} -B$(mingw_build)/ $(ALL_LDFLAGS) + $(CC) $(MINGW_CFLAGS) -o $@ ${wordlist 1,2,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) else - @echo $(CC) -mno-cygwin -o $@ ${wordlist 1,2,$^} ${filter-out -B%, $(ALL_LDFLAGS)};\ - $(CC) $(MINGW_CFLAGS) -o $@ ${wordlist 1,2,$^} -B$(mingw_build)/ $(ALL_LDFLAGS) + @echo $(CC) -mno-cygwin -o $@ ${wordlist 1,2,$^} ${filter-out -B%, $(MINGW_LDFLAGS)};\ + $(CC) $(MINGW_CFLAGS) -o $@ ${wordlist 1,2,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) endif mingw_getopt.o: $(cygwin_source)/getopt.c Index: utils/getfacl.c =================================================================== RCS file: /src/cvsroot/winsup-000106/utils/getfacl.c,v retrieving revision 1.1 diff -u -p -r1.1 getfacl.c --- utils/getfacl.c 2000/01/07 22:56:27 1.1 +++ utils/getfacl.c 2000/01/07 22:59:31 @@ -0,0 +1,124 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +char *permstr (mode_t perm) +{ + static char pbuf[4]; + + pbuf[0] = (perm & S_IREAD) ? 'r' : '-'; + pbuf[1] = (perm & S_IWRITE) ? 'w' : '-'; + pbuf[2] = (perm & S_IEXEC) ? 'x' : '-'; + pbuf[3] = '\0'; + return pbuf; +} + +#if 0 +char *username (uid_t uid) +{ + static char ubuf[256]; + struct passwd *pw; + + if (pw = getpwuid (uid)) + strcpy (ubuf, pw->pw_name); + else + strcpy (ubuf, ""); +} + +char *groupname (gid_t gid) +{ + static char gbuf[256]; + struct group *gr; + + if (gr = getgruid (gid)) + strcpy (gbuf, gr->gr_name); + else + strcpy (gbuf, ""); +} +#endif + +int +main (int argc, char **argv) +{ + extern int optind; + int c, i; + int aopt = 0; + int dopt = 0; + int first = 1; + struct stat st; + aclent_t acls[MAX_ACL_ENTRIES]; + + while ((c = getopt (argc, argv, "ad")) != EOF) + switch (c) + { + case 'a': + aopt = 1; + break; + case 'd': + dopt = 1; + break; + default: + fprintf (stderr, "usage: %s [-ad] file...\n", argv[0]); + return 1; + } + while ((c = optind++) < argc) + { + if (stat (argv[c], &st)) + { + perror (argv[0]); + continue; + } + if (! first) + putchar ('\n'); + first = 0; + printf ("# file: %s\n", argv[c]); + printf ("# owner: %d\n", st.st_uid); + printf ("# group: %d\n", st.st_gid); + if ((c = acl (argv[c], GETACL, MAX_ACL_ENTRIES, acls)) < 0) + { + perror (argv[0]); + continue; + } + for (i = 0; i < c; ++i) + { + if (acls[i].a_type & ACL_DEFAULT) + { + if (aopt) + continue; + printf ("default:"); + } + else if (dopt) + continue; + switch (acls[i].a_type & ~ACL_DEFAULT) + { + case USER_OBJ: + printf ("user::"); + break; + case USER: + printf ("user:%d:", acls[i].a_id); + break; + case GROUP_OBJ: + printf ("group::"); + break; + case GROUP: + printf ("group:%d:", acls[i].a_id); + break; + case CLASS_OBJ: + printf ("mask::"); + break; + case OTHER_OBJ: + printf ("other::"); + break; + } + printf ("%s\n", permstr (acls[i].a_perm)); + } + } + return 0; +} + Index: utils/setfacl.c =================================================================== RCS file: /src/cvsroot/winsup-000106/utils/setfacl.c,v retrieving revision 1.1 diff -u -p -r1.1 setfacl.c --- utils/setfacl.c 2000/01/07 22:56:27 1.1 +++ utils/setfacl.c 2000/01/07 22:59:28 @@ -0,0 +1,377 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOL +#define BOOL int +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef ILLEGAL_MODE +#define ILLEGAL_MODE ((mode_t)0xffffffff) +#endif + +typedef enum { + NoAction, + Set, + Modify, + Delete, + ModNDel, + SetFromFile +} action_t; + +char *myname; + +int usage () +{ + fprintf(stderr, "usage: %s [-r] -s acl_entries file...\n", myname); + fprintf(stderr, " %s [-r] -md acl_entries file...\n", myname); + fprintf(stderr, " %s [-r] -f acl_file file...\n", myname); + return 1; +} + +mode_t getperm (char *in) +{ + if (isdigit (*in) && !in[1]) + { + int i = atoi (in); + if (i < 0 || i > 7) + return ILLEGAL_MODE; + return i << 6 | i << 3 | i; + } + if (strlen (in) != 3) + return ILLEGAL_MODE; + if (!strchr ("r-", in[0]) + || !strchr ("w-", in[1]) + || !strchr ("x-", in[2])) + return ILLEGAL_MODE; + return (in[0] == 'r' ? S_IRUSR | S_IRGRP | S_IROTH : 0) + | (in[1] == 'w' ? S_IWUSR | S_IWGRP | S_IWOTH : 0) + | (in[2] == 'x' ? S_IXUSR | S_IXGRP | S_IXOTH : 0); +} + +BOOL +getaclentry (action_t action, char *c, aclent_t *ace) +{ + char *c2; + + ace->a_type = 0; + ace->a_id = 0; + ace->a_perm = 0; + + if (!strncmp (c, "default:", 8) + || !strncmp (c, "d:", 2)) + { + ace->a_type = ACL_DEFAULT; + c = strchr (c, ':') + 1; + } + if (!strncmp (c, "user:", 5) + || !strncmp (c, "u:", 2)) + { + ace->a_type |= USER_OBJ; + c = strchr (c, ':') + 1; + } + else if (!strncmp (c, "group:", 6) + || !strncmp (c, "g:", 2)) + { + ace->a_type |= GROUP_OBJ; + c = strchr (c, ':') + 1; + } + else if (!strncmp (c, "mask:", 5) + || !strncmp (c, "m:", 2)) + { + if (!(ace->a_type & ACL_DEFAULT)) + return FALSE; + ace->a_type |= CLASS_OBJ; + c = strchr (c, ':') + 1; + } + else if (!strncmp (c, "other:", 6) + || !strncmp (c, "o:", 2)) + { + if (!(ace->a_type & ACL_DEFAULT)) + return FALSE; + ace->a_type |= OTHER_OBJ; + c = strchr (c, ':') + 1; + } + else + return FALSE; + if (ace->a_type & (USER_OBJ | GROUP_OBJ)) + { + if (c2 = strchr (c, ':')) + { + if (action == Delete) + return FALSE; + *c2 = '\0'; + } + else if (action != Delete) + return FALSE; + if (c2 == c) + { + if (action == Delete) + return FALSE; + } + else if (isdigit (*c)) + { + char *c3; + + ace->a_id = strtol (c, &c3, 10); + if (*c3) + return FALSE; + } + else if (ace->a_type & USER_OBJ) + { + struct passwd *pw = getpwnam (c); + if (!pw) + return FALSE; + ace->a_id = pw->pw_uid; + } + else + { + struct group *gr = getgrnam (c); + if (!gr) + return FALSE; + ace->a_id = gr->gr_gid; + } + if (ace->a_type & USER_OBJ) + { + ace->a_type &= ~USER_OBJ; + ace->a_type |= USER; + } + else + { + ace->a_type &= ~GROUP_OBJ; + ace->a_type |= GROUP; + } + if (c2) + c = c2 + 1; + } + if (action == Delete) + { + if ((ace->a_type & (CLASS_OBJ | OTHER_OBJ)) + && *c) + return FALSE; + ace->a_perm = ILLEGAL_MODE; + return TRUE; + } + if ((ace->a_perm = getperm (c)) == ILLEGAL_MODE) + return FALSE; + return TRUE; +} + +BOOL +getaclentries (action_t action, char *buf, aclent_t *acls, int *idx) +{ + char *c; + + if (action == SetFromFile) + { + FILE *fp; + char fbuf[256]; + + if (! (fp = fopen (buf, "r"))) + return FALSE; + while (fgets (fbuf, 256, fp)) + { + if (!getaclentry (action, fbuf, acls + (*idx)++)) + { + fclose (fp); + return FALSE; + } + } + fclose (fp); + } + else + for (c = strtok (buf, ","); c; c = strtok (NULL, ",")) + if (!getaclentry (action, c, acls + (*idx)++)) + return FALSE; + return TRUE; +} + +int +searchace (aclent_t *aclp, int nentries, int type, int id) +{ + 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; +} + +int +modacl (aclent_t *tgt, int tcnt, aclent_t *src, int scnt) +{ + int t, s, i; + + for (s = 0; s < scnt; ++s) + { + t = searchace (tgt, MAX_ACL_ENTRIES, src[s].a_type, + (src[s].a_type & (USER | GROUP)) ? src[s].a_id : -1); + if (t < 0) + return -1; + if (src[s].a_perm == ILLEGAL_MODE) + { + if (t < tcnt) + { + for (i = t + 1; i < tcnt; ++i) + tgt[i - 1] = tgt[i]; + --tcnt; + } + } + else + { + tgt[t] = src[s]; + if (t >= tcnt) + ++tcnt; + } + } + return tcnt; +} + +void +setfacl (action_t action, char *path, aclent_t *acls, int cnt) +{ + aclent_t lacl[MAX_ACL_ENTRIES]; + int lcnt; + + memset (lacl, 0, sizeof lacl); + if (action == Set) + { + if (acl (path, SETACL, cnt, acls)) + perror (myname); + return; + } + if ((lcnt = acl (path, GETACL, MAX_ACL_ENTRIES, lacl)) < 0 + || (lcnt = modacl (lacl, lcnt, acls, cnt)) < 0 + || (lcnt = acl (path, SETACL, lcnt, lacl)) < 0) + perror (myname); +} + +int +main (int argc, char **argv) +{ + extern char *optarg; + extern int optind; + int c; + action_t action = NoAction; + int ropt = 0; + aclent_t acls[MAX_ACL_ENTRIES]; + int aclidx = 0; + + myname = argv[0]; + memset (acls, 0, sizeof acls); + while ((c = getopt (argc, argv, "d:f:m:rs:")) != EOF) + switch (c) + { + case 'd': + if (action == NoAction) + action = Delete; + else if (action == Modify) + action = ModNDel; + else + return usage (); + if (! getaclentries (Delete, optarg, acls, &aclidx)) + { + fprintf (stderr, "%s: illegal acl entries\n", myname); + return 2; + } + break; + case 'f': + if (action == NoAction) + action = Set; + else + return usage (); + if (! getaclentries (SetFromFile, optarg, acls, &aclidx)) + { + fprintf (stderr, "%s: illegal acl entries\n", myname); + return 2; + } + break; + case 'm': + if (action == NoAction) + action = Modify; + else if (action == Delete) + action = ModNDel; + else + return usage (); + if (! getaclentries (Modify, optarg, acls, &aclidx)) + { + fprintf (stderr, "%s: illegal acl entries\n", myname); + return 2; + } + break; + case 'r': + if (!ropt) + ropt = 1; + else + return usage (); + break; + case 's': + if (action == NoAction) + action = Set; + else + return usage (); + break; + if (! getaclentries (Set, optarg, acls, &aclidx)) + { + fprintf (stderr, "%s: illegal acl entries\n", myname); + return 2; + } + default: + return usage (); + } + if (action == NoAction) + return usage (); + if (optind > argc - 1) + return usage (); + if (action == Set) + switch (aclcheck (acls, aclidx, NULL)) + { + case GRP_ERROR: + fprintf (stderr, "%s: more than one group entry.\n", myname); + return 2; + case USER_ERROR: + fprintf (stderr, "%s: more than one user entry.\n", myname); + return 2; + case CLASS_ERROR: + fprintf (stderr, "%s: more than one mask entry.\n", myname); + return 2; + case OTHER_ERROR: + fprintf (stderr, "%s: more than one other entry.\n", myname); + return 2; + case DUPLICATE_ERROR: + fprintf (stderr, "%s: duplicate additional user or group.\n", myname); + return 2; + case ENTRY_ERROR: + fprintf (stderr, "%s: invalid entry type.\n", myname); + return 2; + case MISS_ERROR: + fprintf (stderr, "%s: missing entries.\n", myname); + return 2; + case MEM_ERROR: + fprintf (stderr, "%s: out of memory.\n", myname); + return 2; + default: + break; + } + for (c = optind; c < argc; ++c) + setfacl (action, argv[c], acls, aclidx); + return 0; +} +