diff options
Diffstat (limited to 'winsup/cygwin/security.cc')
-rw-r--r-- | winsup/cygwin/security.cc | 2173 |
1 files changed, 0 insertions, 2173 deletions
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc deleted file mode 100644 index a8d5780..0000000 --- a/winsup/cygwin/security.cc +++ /dev/null @@ -1,2173 +0,0 @@ -/* security.cc: NT security functions - - Copyright 1997, 1998, 1999, 2000 Cygnus Solutions. - - Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de - Extensions by Corinna Vinschen <corinna.vinschen@cityweb.de> - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#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 "cygerrno.h" -#include "fhandler.h" -#include "path.h" -#include "dtable.h" -#include "sync.h" -#include "sigproc.h" -#include "pinfo.h" - -extern BOOL allow_ntea; -BOOL allow_ntsec = FALSE; - -SID_IDENTIFIER_AUTHORITY sid_auth[] = { - {SECURITY_NULL_SID_AUTHORITY}, - {SECURITY_WORLD_SID_AUTHORITY}, - {SECURITY_LOCAL_SID_AUTHORITY}, - {SECURITY_CREATOR_SID_AUTHORITY}, - {SECURITY_NON_UNIQUE_AUTHORITY}, - {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) - -char * -convert_sid_to_string_sid (PSID psid, char *sid_str) -{ - char t[32]; - DWORD i; - - if (!psid || !sid_str) - return NULL; - strcpy (sid_str, "S-1-"); - __small_sprintf(t, "%u", GetSidIdentifierAuthority (psid)->Value[5]); - strcat (sid_str, t); - for (i = 0; i < *GetSidSubAuthorityCount (psid); ++i) - { - __small_sprintf(t, "-%lu", *GetSidSubAuthority (psid, i)); - strcat (sid_str, t); - } - return sid_str; -} - -PSID -get_sid (PSID psid, DWORD s, DWORD cnt, DWORD *r) -{ - DWORD i; - - if (! psid || s > 5 || cnt < 1 || cnt > 8) - return NULL; - - InitializeSid(psid, &sid_auth[s], cnt); - for (i = 0; i < cnt; ++i) - memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD)); - return psid; -} - -PSID -convert_string_sid_to_sid (PSID psid, const char *sid_str) -{ - char sid_buf[256]; - char *t; - DWORD cnt = 0; - DWORD s = 0; - DWORD i, r[8]; - - if (! sid_str || strncmp (sid_str, "S-1-", 4)) - return NULL; - - strcpy (sid_buf, sid_str); - - for (t = sid_buf + 4, i = 0; cnt < 8 && (t = strtok (t, "-")); t = NULL, ++i) - if (i == 0) - s = strtoul (t, NULL, 10); - else - r[cnt++] = strtoul (t, NULL, 10); - - return get_sid (psid, s, cnt, r); -} - -BOOL -get_pw_sid (PSID sid, struct passwd *pw) -{ - char *sp = strrchr (pw->pw_gecos, ','); - - if (!sp) - return FALSE; - return convert_string_sid_to_sid (sid, ++sp) != NULL; -} - -BOOL -get_gr_sid (PSID sid, struct group *gr) -{ - return convert_string_sid_to_sid (sid, gr->gr_passwd) != NULL; -} - -PSID -get_admin_sid () -{ - static NO_COPY char admin_sid_buf[MAX_SID_LEN]; - static NO_COPY PSID admin_sid = NULL; - - if (!admin_sid) - { - admin_sid = (PSID) admin_sid_buf; - convert_string_sid_to_sid (admin_sid, "S-1-5-32-544"); - } - return admin_sid; -} - -PSID -get_system_sid () -{ - static NO_COPY char system_sid_buf[MAX_SID_LEN]; - static NO_COPY PSID system_sid = NULL; - - if (!system_sid) - { - system_sid = (PSID) system_sid_buf; - convert_string_sid_to_sid (system_sid, "S-1-5-18"); - } - return system_sid; -} - -PSID -get_creator_owner_sid () -{ - static NO_COPY char owner_sid_buf[MAX_SID_LEN]; - static NO_COPY PSID owner_sid = NULL; - - if (!owner_sid) - { - owner_sid = (PSID) owner_sid_buf; - convert_string_sid_to_sid (owner_sid, "S-1-3-0"); - } - return owner_sid; -} - -PSID -get_world_sid () -{ - static NO_COPY char world_sid_buf[MAX_SID_LEN]; - static NO_COPY PSID world_sid = NULL; - - if (!world_sid) - { - world_sid = (PSID) world_sid_buf; - convert_string_sid_to_sid (world_sid, "S-1-1-0"); - } - return world_sid; -} - -int passwd_sem = 0; -int group_sem = 0; - -static int -get_id_from_sid (PSID psid, BOOL search_grp, int *type) -{ - if (!IsValidSid (psid)) - { - __seterrno (); - small_printf ("IsValidSid failed with %E"); - return -1; - } - - /* First try to get SID from passwd or group entry */ - if (allow_ntsec) - { - char sidbuf[MAX_SID_LEN]; - PSID sid = (PSID) sidbuf; - int id = -1; - - if (! search_grp) - { - if (passwd_sem > 0) - return 0; - ++passwd_sem; - - struct passwd *pw; - while ((pw = getpwent ()) != NULL) - { - if (get_pw_sid (sid, pw) && EqualSid (psid, sid)) - { - id = pw->pw_uid; - break; - } - } - endpwent (); - --passwd_sem; - if (id >= 0) - { - if (type) - *type = USER; - return id; - } - } - if (search_grp || type) - { - if (group_sem > 0) - return 0; - ++group_sem; - - struct group *gr; - while ((gr = getgrent ()) != NULL) - { - if (get_gr_sid (sid, gr) && EqualSid (psid, sid)) - { - id = gr->gr_gid; - break; - } - } - endgrent (); - --group_sem; - if (id >= 0) - { - if (type) - *type = GROUP; - return id; - } - } - } - - /* We use the RID as default UID/GID */ - int id = *GetSidSubAuthority(psid, *GetSidSubAuthorityCount(psid) - 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) - { - 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, &acc_len, - domain, &dom_len, &acc_type)) - { - __seterrno (); - return -1; - } - - switch (acc_type) - { - case SidTypeGroup: - 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: - 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 -lookup_name (const char *name, const char *logsrv, PSID ret_sid) -{ - char sidbuf[MAX_SID_LEN]; - PSID sid = (PSID) sidbuf; - DWORD sidlen; - char domuser[MAX_COMPUTERNAME_LENGTH+MAX_USER_NAME+1]; - char dom[MAX_COMPUTERNAME_LENGTH+1]; - DWORD domlen; - SID_NAME_USE acc_type; - - debug_printf ("name : %s", name ? name : "NULL"); - - if (! name) - return FALSE; - - if (*myself->domain) - { - strcat (strcat (strcpy (domuser, myself->domain), "\\"), name); - if (LookupAccountName (NULL, domuser, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), - &acc_type) - && legal_sid_type (acc_type)) - goto got_it; - if (logsrv && *logsrv - && LookupAccountName (logsrv, domuser, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = MAX_COMPUTERNAME_LENGTH,&domlen), - &acc_type) - && legal_sid_type (acc_type)) - goto got_it; - } - if (logsrv && *logsrv) - { - if (LookupAccountName (logsrv, name, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), - &acc_type) - && legal_sid_type (acc_type)) - goto got_it; - if (acc_type == SidTypeDomain) - { - strcat (strcat (strcpy (domuser, dom), "\\"), name); - if (LookupAccountName (logsrv, domuser, - sid,(sidlen = MAX_SID_LEN, &sidlen), - dom,(domlen = MAX_COMPUTERNAME_LENGTH,&domlen), - &acc_type)) - goto got_it; - } - } - if (LookupAccountName (NULL, name, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = 100, &domlen), - &acc_type) - && legal_sid_type (acc_type)) - goto got_it; - if (acc_type == SidTypeDomain) - { - strcat (strcat (strcpy (domuser, dom), "\\"), name); - if (LookupAccountName (NULL, domuser, - sid, (sidlen = MAX_SID_LEN, &sidlen), - dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), - &acc_type)) - goto got_it; - } - debug_printf ("LookupAccountName(%s) %E", name); - __seterrno (); - return FALSE; - -got_it: - debug_printf ("sid : [%d]", *GetSidSubAuthority((PSID) sid, - *GetSidSubAuthorityCount((PSID) sid) - 1)); - - if (ret_sid) - memcpy (ret_sid, sid, sidlen); - - return TRUE; -} - -extern "C" -void -cygwin_set_impersonation_token (const HANDLE hToken) -{ - debug_printf ("set_impersonation_token (%d)", hToken); - if (myself->token != hToken) - { - if (myself->token != INVALID_HANDLE_VALUE) - CloseHandle (myself->token); - myself->token = hToken; - myself->impersonated = FALSE; - } -} - -extern "C" -HANDLE -cygwin_logon_user (const struct passwd *pw, const char *password) -{ - if (os_being_run != winNT) - { - set_errno (ENOSYS); - return INVALID_HANDLE_VALUE; - } - if (!pw) - { - set_errno (EINVAL); - return INVALID_HANDLE_VALUE; - } - - char *c, *nt_user, *nt_domain = NULL; - char usernamebuf[256]; - HANDLE hToken; - - strcpy (usernamebuf, pw->pw_name); - if (pw->pw_gecos) - { - if ((c = strstr (pw->pw_gecos, "U-")) != NULL && - (c == pw->pw_gecos || c[-1] == ',')) - { - usernamebuf[0] = '\0'; - strncat (usernamebuf, c + 2, 255); - if ((c = strchr (usernamebuf, ',')) != NULL) - *c = '\0'; - } - } - nt_user = usernamebuf; - if ((c = strchr (nt_user, '\\')) != NULL) - { - nt_domain = nt_user; - *c = '\0'; - nt_user = c + 1; - } - if (! LogonUserA (nt_user, nt_domain, (char *) password, - LOGON32_LOGON_INTERACTIVE, - LOGON32_PROVIDER_DEFAULT, - &hToken) - || !SetHandleInformation (hToken, - HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT)) - { - __seterrno (); - return INVALID_HANDLE_VALUE; - } - debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name); - return hToken; -} - -/* read_sd reads a security descriptor from a file. - In case of error, -1 is returned and errno is set. - If sd_buf is too small, 0 is returned and sd_size - is set to the needed buffer size. - On success, 1 is returned. - - GetFileSecurity() is used instead of BackupRead() - to avoid access denied errors if the caller has - not the permission to open that file for read. - - Originally the function should return the size - of the SD on success. Unfortunately NT returns - 0 in `len' on success, while W2K returns the - correct size! -*/ - -LONG -read_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size) -{ - /* Check parameters */ - if (! sd_size) - { - set_errno (EINVAL); - return -1; - } - - debug_printf("file = %s", file); - - DWORD len = 0; - if (! GetFileSecurity (file, - OWNER_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | DACL_SECURITY_INFORMATION, - sd_buf, *sd_size, &len)) - { - __seterrno (); - return -1; - } - debug_printf("file = %s: len=%d", file, len); - if (len > *sd_size) - { - *sd_size = len; - return 0; - } - return 1; -} - -LONG -write_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size) -{ - /* Check parameters */ - if (! sd_buf || ! sd_size) - { - set_errno (EINVAL); - return -1; - } - - HANDLE fh; - fh = CreateFile (file, - WRITE_OWNER | WRITE_DAC, - FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_none_nih, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, - NULL); - - if (fh == INVALID_HANDLE_VALUE) - { - __seterrno (); - return -1; - } - - LPVOID context = NULL; - DWORD bytes_written = 0; - WIN32_STREAM_ID header; - - memset (&header, 0, sizeof (header)); - /* write new security info header */ - header.dwStreamId = BACKUP_SECURITY_DATA; - header.dwStreamAttributes = STREAM_CONTAINS_SECURITY; - header.Size.HighPart = 0; - header.Size.LowPart = sd_size; - header.dwStreamNameSize = 0; - if (!BackupWrite (fh, (LPBYTE) &header, - 3 * sizeof (DWORD) + sizeof (LARGE_INTEGER), - &bytes_written, FALSE, TRUE, &context)) - { - __seterrno (); - CloseHandle (fh); - return -1; - } - - /* write new security descriptor */ - if (!BackupWrite (fh, (LPBYTE) sd_buf, - header.Size.LowPart + header.dwStreamNameSize, - &bytes_written, FALSE, TRUE, &context)) - { - /* Samba returns ERROR_NOT_SUPPORTED. - FAT returns ERROR_INVALID_SECURITY_DESCR. - This shouldn't return as error, but better be ignored. */ - DWORD ret = GetLastError (); - if (ret != ERROR_NOT_SUPPORTED && ret != ERROR_INVALID_SECURITY_DESCR) - { - __seterrno (); - BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context); - CloseHandle (fh); - return -1; - } - } - - /* terminate the restore process */ - BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context); - CloseHandle (fh); - return 0; -} - -int -set_process_privileges () -{ - HANDLE hProcess = NULL; - HANDLE hToken = NULL; - LUID restore_priv; - LUID backup_priv; - char buf[sizeof (TOKEN_PRIVILEGES) + 2 * sizeof (LUID_AND_ATTRIBUTES)]; - TOKEN_PRIVILEGES *new_priv = (TOKEN_PRIVILEGES *) buf; - int ret = -1; - - hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId ()); - if (! hProcess) - { - __seterrno (); - goto out; - } - - if (! OpenProcessToken (hProcess, - TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, - &hToken)) - { - __seterrno (); - goto out; - } - - if (! LookupPrivilegeValue (NULL, SE_RESTORE_NAME, &restore_priv)) - { - __seterrno (); - goto out; - } - if (! LookupPrivilegeValue (NULL, SE_BACKUP_NAME, &backup_priv)) - { - __seterrno (); - goto out; - } - - new_priv->PrivilegeCount = 2; - new_priv->Privileges[0].Luid = restore_priv; - new_priv->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - new_priv->Privileges[1].Luid = backup_priv; - new_priv->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED; - - if (! AdjustTokenPrivileges (hToken, FALSE, new_priv, 0, NULL, NULL)) - { - __seterrno (); - goto out; - } - - ret = 0; - - if (ret == -1) - __seterrno (); - -out: - if (hToken) - CloseHandle (hToken); - if (hProcess) - CloseHandle (hProcess); - - syscall_printf ("%d = set_process_privileges ()", ret); - return ret; -} - -static int -get_nt_attribute (const char *file, int *attribute, - uid_t *uidret, gid_t *gidret) -{ - if (os_being_run != winNT) - return 0; - - syscall_printf ("file: %s", file); - - /* Yeah, sounds too much, but I've seen SDs of 2100 bytes! */ - 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; - - if (! GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) - debug_printf ("GetSecurityDescriptorOwner %E"); - if (! GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) - debug_printf ("GetSecurityDescriptorGroup %E"); - - PACL acl; - BOOL acl_exists; - - if (! GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) - { - __seterrno (); - debug_printf ("GetSecurityDescriptorDacl %E"); - return -1; - } - - uid_t uid = get_uid_from_sid (owner_sid); - gid_t gid = get_gid_from_sid (group_sid); - if (uidret) - *uidret = uid; - if (gidret) - *gidret = gid; - - if (! attribute) - { - syscall_printf ("file: %s uid %d, gid %d", file, uid, gid); - return 0; - } - - BOOL grp_member = is_grp_member (uid, gid); - - if (! acl_exists || ! acl) - { - *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - syscall_printf ("file: %s No ACL = %x, uid %d, gid %d", - file, *attribute, uid, gid); - return 0; - } - - ACCESS_ALLOWED_ACE *ace; - int allow = 0; - int deny = 0; - int *flags, *anti; - - for (DWORD i = 0; i < acl->AceCount; ++i) - { - 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; - } - - 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, uid %d, gid %d", file, *attribute, uid, gid); - return 0; -} - -int -get_file_attribute (int use_ntsec, const char *file, - int *attribute, uid_t *uidret, gid_t *gidret) -{ - if (use_ntsec && allow_ntsec) - return get_nt_attribute (file, attribute, uidret, gidret); - - if (uidret) - *uidret = getuid (); - if (gidret) - *gidret = getgid (); - - if (! attribute) - return 0; - - int res = NTReadEA (file, ".UNIXATTR", - (char *) attribute, sizeof (*attribute)); - - // symlinks are anything for everyone! - if ((*attribute & S_IFLNK) == S_IFLNK) - *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - - if (res <= 0) - set_errno (ENOSYS); - return res > 0 ? 0 : -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; - - if (! sd_ret || ! sd_size_ret) - { - set_errno (EINVAL); - return NULL; - } - - // Get SID and name of new owner - char owner[MAX_USER_NAME]; - char *owner_sid_buf[MAX_SID_LEN]; - PSID owner_sid = NULL; - struct passwd *pw = getpwuid (uid); - strcpy (owner, pw ? pw->pw_name : getlogin ()); - owner_sid = (PSID) owner_sid_buf; - if ((! pw || ! get_pw_sid (owner_sid, pw)) - && ! 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)) - return NULL; - } - else - debug_printf ("no group"); - - // Initialize local security descriptor - SECURITY_DESCRIPTOR sd; - PSECURITY_DESCRIPTOR psd = NULL; - if (! InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) - { - __seterrno (); - return NULL; - } - - if (! SetSecurityDescriptorOwner(&sd, owner_sid, FALSE)) - { - __seterrno (); - return NULL; - } - if (group_sid - && ! SetSecurityDescriptorGroup(&sd, group_sid, FALSE)) - { - __seterrno (); - return NULL; - } - - // Initialize local access control list - char acl_buf[3072]; - PACL acl = (PACL) acl_buf; - if (! InitializeAcl (acl, 3072, ACL_REVISION)) - { - __seterrno (); - return NULL; - } - - // 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_IFDIR)) - 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_WRITE | 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_WRITE | 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); - - // Construct appropriate inherit attribute - DWORD inherit = (attribute & S_IFDIR) ? INHERIT_ALL : DONT_INHERIT; - - // Set deny ACE for owner - if (owner_deny - && ! add_access_denied_ace (acl, ace_off++, owner_deny, - owner_sid, acl_len, inherit)) - return NULL; - // Set allow ACE for owner - if (! add_access_allowed_ace (acl, ace_off++, owner_allow, - owner_sid, acl_len, inherit)) - return NULL; - // Set deny ACE for group - if (group_deny - && ! add_access_denied_ace (acl, ace_off++, group_deny, - group_sid, acl_len, inherit)) - return NULL; - // Set allow ACE for group - if (! add_access_allowed_ace (acl, ace_off++, group_allow, - group_sid, acl_len, inherit)) - return NULL; - - // 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"); - - // 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)) - { - 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 ACCESS_DENIED_ACE to the beginning but - // behind the owner_deny, ACCESS_ALLOWED_ACE to the end - // but in front of the `everyone' ACE. - if (! AddAce(acl, ACL_REVISION, - ace->Header.AceType == ACCESS_DENIED_ACE_TYPE ? - (owner_deny ? 1 : 0) : MAXDWORD, - (LPVOID) ace, ace->Header.AceSize)) - { - __seterrno (); - return NULL; - } - acl_len += ace->Header.AceSize; - ++ace_off; - } - - // Set allow ACE for everyone - if (! add_access_allowed_ace (acl, ace_off++, other_allow, - get_world_sid (), acl_len, inherit)) - return NULL; - - // 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 NULL; - } - - // Make self relative security descriptor - *sd_size_ret = 0; - MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret); - if (*sd_size_ret <= 0) - { - __seterrno (); - 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); - - return psd; -} - -static int -set_nt_attribute (const char *file, uid_t uid, gid_t gid, - const char *logsrv, int attribute) -{ - if (os_being_run != winNT) - return 0; - - 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; - } - - sd_size = 4096; - if (! (psd = alloc_sd (uid, gid, logsrv, attribute, psd, &sd_size))) - return -1; - - return write_sd (file, psd, sd_size); -} - -int -set_file_attribute (int use_ntsec, const char *file, - uid_t uid, gid_t gid, - int attribute, const char *logsrv) -{ - // symlinks are anything for everyone! - if ((attribute & S_IFLNK) == S_IFLNK) - attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - - if (!use_ntsec || !allow_ntsec) - { - if (! NTWriteEA (file, ".UNIXATTR", - (char *) &attribute, sizeof (attribute))) - { - __seterrno (); - return -1; - } - return 0; - } - - int ret = set_nt_attribute (file, uid, gid, logsrv, attribute); - syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)", - ret, file, uid, gid, attribute); - return ret; -} - -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 -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 -setacl (const char *file, int nentries, aclent_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; - } - 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; - 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 - | DELETE | FILE_DELETE_CHILD; - if (aclbufp[i].a_perm & S_IXOTH) - allow |= FILE_GENERIC_EXECUTE; - // Set inherit property - DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT) - ? INHERIT_ONLY : DONT_INHERIT; - // 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 - && pos < nentries - && aclbufp[i].a_perm == aclbufp[pos].a_perm) - { - inheritance = INHERIT_ALL; - // 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_sid, acl_len, inheritance)) - return -1; - break; - case USER: - 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, inheritance)) - return -1; - break; - case GROUP_OBJ: - case DEF_GROUP_OBJ: - if (! add_access_allowed_ace (acl, ace_off++, allow, - group_sid, acl_len, inheritance)) - return -1; - break; - case GROUP: - 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, inheritance)) - return -1; - break; - case OTHER_OBJ: - case DEF_OTHER_OBJ: - if (! add_access_allowed_ace (acl, ace_off++, allow, - get_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); -} - -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 -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 = read_sd (file, psd, &sd_size)) <= 0) - { - debug_printf ("read_sd %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; -} - -int -acl_access (const char *path, int flags) -{ - aclent_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 - char owner_sidbuf[MAX_SID_LEN]; - PSID owner_sid = (PSID) owner_sidbuf; - char group_sidbuf[MAX_SID_LEN]; - PSID group_sid = (PSID) group_sidbuf; - struct passwd *pw; - struct group *gr = NULL; - - if (group_sem > 0) - continue; - ++group_sem; - if ((pw = getpwuid (acls[i].a_id)) != NULL - && get_pw_sid (owner_sid, pw)) - { - while ((gr = getgrent ())) - if (get_gr_sid (group_sid, gr) - && EqualSid (owner_sid, group_sid) - && is_grp_member (myself->uid, gr->gr_gid)) - break; - endgrent (); - } - --group_sem; - 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_IREAD)) - && (!(flags & W_OK) || (acls[i].a_perm & S_IWRITE)) - && (!(flags & X_OK) || (acls[i].a_perm & S_IEXEC))) - return 0; - } - set_errno (EACCES); - return -1; -} - -static -int -acl_worker (const char *path, int cmd, int nentries, aclent_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 ()) - { - struct stat st; - int ret = -1; - - switch (cmd) - { - case SETACL: - set_errno (ENOSYS); - break; - case GETACL: - if (nentries < 1) - set_errno (EINVAL); - else if ((nofollow && ! lstat (path, &st)) - || (!nofollow && ! 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 -acl (const char *path, int cmd, int nentries, aclent_t *aclbufp) -{ - return acl_worker (path, cmd, nentries, aclbufp, 0); -} - -extern "C" -int -lacl (const char *path, int cmd, int nentries, aclent_t *aclbufp) -{ - return acl_worker (path, cmd, nentries, aclbufp, 1); -} - -extern "C" -int -facl (int fd, int cmd, int nentries, aclent_t *aclbufp) -{ - if (fdtab.not_open (fd)) - { - syscall_printf ("-1 = facl (%d)", fd); - set_errno (EBADF); - return -1; - } - const char *path = fdtab[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_worker (path, cmd, nentries, aclbufp, 0); -} - -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 -#if 0 - // These checks are not ok yet since CLASS_OBJ isn't fully implemented. - || (has_ug_objs && !has_class_obj) - || (has_def_ug_objs && !has_def_class_obj) -#endif - ) - { - 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, 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: - __small_sprintf (buf + strlen (buf), "user::%s", - permtostr (aclbufp[pos].a_perm)); - break; - case USER: - __small_sprintf (buf + strlen (buf), "user:%d:%s", - aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); - break; - case GROUP_OBJ: - __small_sprintf (buf + strlen (buf), "group::%s", - permtostr (aclbufp[pos].a_perm)); - break; - case GROUP: - __small_sprintf (buf + strlen (buf), "group:%d:%s", - aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); - break; - case CLASS_OBJ: - __small_sprintf (buf + strlen (buf), "mask::%s", - permtostr (aclbufp[pos].a_perm)); - break; - case OTHER_OBJ: - __small_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 *) -{ - 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; -} - |