/* Convert generic rights into standard access rights */ void convert_generic_sd( struct security_descriptor *sd ) { const ACL *dacl; int present; dacl = sd_get_dacl( sd, &present ); if (present && dacl) { const ACE_HEADER *ace = (const ACE_HEADER *)(dacl + 1); ULONG i; for (i = 0; i < dacl->AceCount; i++, ace = ace_next( ace )) { DWORD *mask = (DWORD *)(ace + 1); *mask = generic_file_map_access( *mask ); } } }
mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner ) { mode_t new_mode = 0; mode_t bits_to_set = ~0; mode_t mode; int present; const ACL *dacl = sd_get_dacl( sd, &present ); const SID *user = token_get_user( current->process->token ); if (present && dacl) { const ACE_HEADER *ace = (const ACE_HEADER *)(dacl + 1); ULONG i; for (i = 0; i < dacl->AceCount; i++, ace = ace_next( ace )) { const ACCESS_ALLOWED_ACE *aa_ace; const ACCESS_DENIED_ACE *ad_ace; const SID *sid; if (ace->AceFlags & INHERIT_ONLY_ACE) continue; switch (ace->AceType) { case ACCESS_DENIED_ACE_TYPE: ad_ace = (const ACCESS_DENIED_ACE *)ace; sid = (const SID *)&ad_ace->SidStart; mode = file_access_to_mode( ad_ace->Mask ); if (security_equal_sid( sid, security_world_sid )) { bits_to_set &= ~((mode << 6) | (mode << 3) | mode); /* all */ } else if ((security_equal_sid( user, owner ) && token_sid_present( current->process->token, sid, TRUE ))) { bits_to_set &= ~((mode << 6) | (mode << 3)); /* user + group */ } else if (security_equal_sid( sid, owner )) { bits_to_set &= ~(mode << 6); /* user only */ } break; case ACCESS_ALLOWED_ACE_TYPE: aa_ace = (const ACCESS_ALLOWED_ACE *)ace; sid = (const SID *)&aa_ace->SidStart; mode = file_access_to_mode( aa_ace->Mask ); if (security_equal_sid( sid, security_world_sid )) { mode = (mode << 6) | (mode << 3) | mode; /* all */ new_mode |= mode & bits_to_set; bits_to_set &= ~mode; } else if ((security_equal_sid( user, owner ) && token_sid_present( current->process->token, sid, FALSE ))) { mode = (mode << 6) | (mode << 3); /* user + group */ new_mode |= mode & bits_to_set; bits_to_set &= ~mode; } else if (security_equal_sid( sid, owner )) { mode = (mode << 6); /* user only */ new_mode |= mode & bits_to_set; bits_to_set &= ~mode; } break; } } } else /* no ACL means full access rights to anyone */ new_mode = S_IRWXU | S_IRWXG | S_IRWXO; return new_mode; }
struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID *group ) { struct security_descriptor *sd; size_t dacl_size; ACE_HEADER *current_ace; ACCESS_ALLOWED_ACE *aaa; ACL *dacl; SID *sid; char *ptr; const SID *world_sid = security_world_sid; const SID *local_system_sid = security_local_system_sid; dacl_size = sizeof(ACL) + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + security_sid_len( local_system_sid ); if (mode & S_IRWXU) dacl_size += FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + security_sid_len( user ); if ((!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH))) || (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH))) || (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))) dacl_size += FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart) + security_sid_len( user ); if (mode & S_IRWXO) dacl_size += FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + security_sid_len( world_sid ); sd = mem_alloc( sizeof(struct security_descriptor) + security_sid_len( user ) + security_sid_len( group ) + dacl_size ); if (!sd) return sd; sd->control = SE_DACL_PRESENT; sd->owner_len = security_sid_len( user ); sd->group_len = security_sid_len( group ); sd->sacl_len = 0; sd->dacl_len = dacl_size; ptr = (char *)(sd + 1); memcpy( ptr, user, sd->owner_len ); ptr += sd->owner_len; memcpy( ptr, group, sd->group_len ); ptr += sd->group_len; dacl = (ACL *)ptr; dacl->AclRevision = ACL_REVISION; dacl->Sbz1 = 0; dacl->AclSize = dacl_size; dacl->AceCount = 1 + (mode & S_IRWXU ? 1 : 0) + (mode & S_IRWXO ? 1 : 0); if ((!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH))) || (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH))) || (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))) dacl->AceCount++; dacl->Sbz2 = 0; /* always give FILE_ALL_ACCESS for Local System */ aaa = (ACCESS_ALLOWED_ACE *)(dacl + 1); current_ace = &aaa->Header; aaa->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; aaa->Header.AceFlags = (mode & S_IFDIR) ? OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE : 0; aaa->Header.AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + security_sid_len( local_system_sid ); aaa->Mask = FILE_ALL_ACCESS; sid = (SID *)&aaa->SidStart; memcpy( sid, local_system_sid, security_sid_len( local_system_sid )); if (mode & S_IRWXU) { /* appropriate access rights for the user */ aaa = (ACCESS_ALLOWED_ACE *)ace_next( current_ace ); current_ace = &aaa->Header; aaa->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; aaa->Header.AceFlags = (mode & S_IFDIR) ? OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE : 0; aaa->Header.AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + security_sid_len( user ); aaa->Mask = WRITE_DAC | WRITE_OWNER; if (mode & S_IRUSR) aaa->Mask |= FILE_GENERIC_READ | FILE_GENERIC_EXECUTE; if (mode & S_IWUSR) aaa->Mask |= FILE_GENERIC_WRITE | DELETE | FILE_DELETE_CHILD; sid = (SID *)&aaa->SidStart; memcpy( sid, user, security_sid_len( user )); } if ((!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH))) || (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH))) || (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))) { /* deny just in case the user is a member of the group */ ACCESS_DENIED_ACE *ada = (ACCESS_DENIED_ACE *)ace_next( current_ace ); current_ace = &ada->Header; ada->Header.AceType = ACCESS_DENIED_ACE_TYPE; ada->Header.AceFlags = (mode & S_IFDIR) ? OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE : 0; ada->Header.AceSize = FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart) + security_sid_len( user ); ada->Mask = 0; if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH))) ada->Mask |= FILE_GENERIC_READ | FILE_GENERIC_EXECUTE; if (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IROTH))) ada->Mask |= FILE_GENERIC_WRITE | DELETE | FILE_DELETE_CHILD; ada->Mask &= ~STANDARD_RIGHTS_ALL; /* never deny standard rights */ sid = (SID *)&ada->SidStart; memcpy( sid, user, security_sid_len( user )); } if (mode & S_IRWXO) { /* appropriate access rights for Everyone */ aaa = (ACCESS_ALLOWED_ACE *)ace_next( current_ace ); current_ace = &aaa->Header; aaa->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; aaa->Header.AceFlags = (mode & S_IFDIR) ? OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE : 0; aaa->Header.AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + security_sid_len( world_sid ); aaa->Mask = 0; if (mode & S_IROTH) aaa->Mask |= FILE_GENERIC_READ | FILE_GENERIC_EXECUTE; if (mode & S_IWOTH) aaa->Mask |= FILE_GENERIC_WRITE | DELETE | FILE_DELETE_CHILD; sid = (SID *)&aaa->SidStart; memcpy( sid, world_sid, security_sid_len( world_sid )); } return sd; }
struct security_descriptor *get_xattr_acls( int fd, const SID *user, const SID *group ) { int dacl_size = sizeof(ACL), n; int offset, type, flags, mask, rev, ia, sa; char buffer[XATTR_SIZE_MAX + 1], *p, *ptr; struct security_descriptor *sd; ACL *dacl; n = xattr_fget( fd, XATTR_USER_PREFIX "wine.acl", buffer, sizeof(buffer) - 1 ); if (n == -1) return NULL; buffer[n] = 0; /* ensure NULL terminated buffer for string functions */ p = buffer; do { int sub_authority_count = 0; if (sscanf(p, "%x,%x,%x,S-%u-%d%n", &type, &flags, &mask, &rev, &ia, &offset) != 5) return NULL; p += offset; while (sscanf(p, "-%u%n", &sa, &offset) == 1) { p += offset; sub_authority_count++; } if (*p == ';') p++; else if (*p) return NULL; /* verify that the SubAuthorityCount does not exceed the maximum permitted value */ if (sub_authority_count > SID_MAX_SUB_AUTHORITIES) continue; switch (type) { case ACCESS_DENIED_ACE_TYPE: dacl_size += FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority[sub_authority_count]); break; case ACCESS_ALLOWED_ACE_TYPE: dacl_size += FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority[sub_authority_count]); break; default: continue; } } while (*p); n = sizeof(struct security_descriptor) + FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]) + FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]) + dacl_size; sd = mem_alloc( n ); if (!sd) return NULL; sd->control = SE_DACL_PRESENT; sd->owner_len = FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]); sd->group_len = FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]); sd->sacl_len = 0; sd->dacl_len = dacl_size; ptr = (char *)(sd + 1); memcpy( ptr, user, sd->owner_len ); ptr += sd->owner_len; memcpy( ptr, group, sd->group_len ); ptr += sd->group_len; dacl = (ACL *)ptr; dacl->AclRevision = ACL_REVISION; dacl->Sbz1 = 0; dacl->AclSize = dacl_size; dacl->AceCount = 0; dacl->Sbz2 = 0; ptr = (char *)(dacl + 1); p = buffer; do { char sid_buffer[sizeof(SID) + sizeof(ULONG) * SID_MAX_SUB_AUTHORITIES]; SID *sid = (SID *)sid_buffer; int sub_authority_count = 0; if (sscanf(p, "%x,%x,%x,S-%u-%d%n", &type, &flags, &mask, &rev, &ia, &offset) != 5) goto err; p += offset; while (sscanf(p, "-%u%n", &sa, &offset) == 1) { p += offset; if (sub_authority_count < SID_MAX_SUB_AUTHORITIES) sid->SubAuthority[sub_authority_count] = sa; sub_authority_count++; } if (*p == ';') p++; else if (*p) goto err; if (sub_authority_count > SID_MAX_SUB_AUTHORITIES) continue; sid->Revision = rev; sid->IdentifierAuthority.Value[0] = 0; sid->IdentifierAuthority.Value[1] = 0; sid->IdentifierAuthority.Value[2] = HIBYTE(HIWORD(ia)); sid->IdentifierAuthority.Value[3] = LOBYTE(HIWORD(ia)); sid->IdentifierAuthority.Value[4] = HIBYTE(LOWORD(ia)); sid->IdentifierAuthority.Value[5] = LOBYTE(LOWORD(ia)); sid->SubAuthorityCount = sub_authority_count; /* Handle the specific ACE */ switch (type) { case ACCESS_DENIED_ACE_TYPE: { ACCESS_DENIED_ACE *ada = (ACCESS_DENIED_ACE *)ptr; ada->Header.AceType = type; ada->Header.AceFlags = flags; ada->Header.AceSize = FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]); ada->Mask = mask; memcpy( &ada->SidStart, sid, FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]) ); } break; case ACCESS_ALLOWED_ACE_TYPE: { ACCESS_ALLOWED_ACE *aaa = (ACCESS_ALLOWED_ACE *)ptr; aaa->Header.AceType = type; aaa->Header.AceFlags = flags; aaa->Header.AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]); aaa->Mask = mask; memcpy( &aaa->SidStart, sid, FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]) ); } break; default: continue; } ptr = (char *)ace_next( (ACE_HEADER *)ptr ); dacl->AceCount++; } while (*p); if (sd_is_valid( sd, n )) return sd; err: free( sd ); return NULL; }
struct security_descriptor *file_combine_sds( const struct security_descriptor *parent_sd, const struct security_descriptor *child_sd ) { size_t dacl_size = sizeof(ACL), ace_count = 0; const struct security_descriptor *old_sd; struct security_descriptor *sd = NULL; const ACL *child_dacl, *parent_dacl; int child_present, parent_present; const SID *user, *group; const ACE_HEADER *old_ace; ACE_HEADER *ace; ACL *dacl; char *ptr; ULONG i; child_dacl = sd_get_dacl( child_sd, &child_present ); if (child_present && child_dacl) { old_ace = (const ACE_HEADER *)(child_dacl + 1); for (i = 0; i < child_dacl->AceCount; i++, old_ace = ace_next( old_ace )) { ace_count++; dacl_size += sizeof(ACE_HEADER) + old_ace->AceSize; } } parent_dacl = sd_get_dacl( parent_sd, &parent_present ); if (parent_present && parent_dacl) { old_ace = (const ACE_HEADER *)(parent_dacl + 1); for (i = 0; i < parent_dacl->AceCount; i++, old_ace = ace_next( old_ace )) { ace_count++; dacl_size += sizeof(ACE_HEADER) + old_ace->AceSize; } } if(!ace_count) return sd; /* No inheritance */ /* FIXME: should use set_info flags? */ if (child_present && child_dacl) old_sd = child_sd; else old_sd = parent_sd; /* Fill in the security descriptor so that it is compatible with our DACL */ user = (const SID *)(old_sd + 1); group = (const SID *)((char *)(old_sd + 1) + old_sd->owner_len); sd = mem_alloc( sizeof(struct security_descriptor) + old_sd->owner_len + old_sd->group_len + dacl_size ); if (!sd) return sd; sd->control = SE_DACL_PRESENT; sd->owner_len = old_sd->owner_len; sd->group_len = old_sd->group_len; sd->sacl_len = 0; sd->dacl_len = dacl_size; ptr = (char *)(sd + 1); memcpy( ptr, user, sd->owner_len ); ptr += sd->owner_len; memcpy( ptr, group, sd->group_len ); ptr += sd->group_len; dacl = (ACL *)ptr; dacl->AclRevision = ACL_REVISION; dacl->Sbz1 = 0; dacl->AclSize = dacl_size; dacl->AceCount = ace_count; dacl->Sbz2 = 0; ace = (ACE_HEADER *)(dacl + 1); if (parent_present && parent_dacl) { /* Build the new DACL, inheriting from the parent's information */ old_ace = (const ACE_HEADER *)(parent_dacl + 1); for (i = 0; i < parent_dacl->AceCount; i++, old_ace = ace_next( old_ace )) { ace->AceType = old_ace->AceType; ace->AceFlags = old_ace->AceFlags; ace->AceSize = old_ace->AceSize; memcpy( ace + 1, old_ace + 1, old_ace->AceSize - sizeof(ACE_HEADER)); ace = (ACE_HEADER *)ace_next( ace ); } } if (child_present && child_dacl) { /* Build the new DACL, inheriting from the child's information */ old_ace = (const ACE_HEADER *)(child_dacl + 1); for (i = 0; i < child_dacl->AceCount; i++, old_ace = ace_next( old_ace )) { ace->AceType = old_ace->AceType; ace->AceFlags = old_ace->AceFlags; ace->AceSize = old_ace->AceSize; memcpy( ace + 1, old_ace + 1, old_ace->AceSize - sizeof(ACE_HEADER)); ace = (ACE_HEADER *)ace_next( ace ); } } return sd; }
struct security_descriptor *inherit_sd( const struct security_descriptor *parent_sd, int is_dir ) { const DWORD inheritance_mask = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; struct security_descriptor *sd = NULL; const ACL *parent_dacl; int present; ACL *dacl; parent_dacl = sd_get_dacl( parent_sd, &present ); if (present && parent_dacl) { size_t dacl_size = sizeof(ACL), ace_count = 0; const ACE_HEADER *parent_ace; const SID *user, *group; ACE_HEADER *ace; char *ptr; ULONG i; /* Calculate the size of the DACL */ parent_ace = (const ACE_HEADER *)(parent_dacl + 1); for (i = 0; i < parent_dacl->AceCount; i++, parent_ace = ace_next( parent_ace )) { if (!(parent_ace->AceFlags & inheritance_mask)) continue; ace_count++; dacl_size += parent_ace->AceSize; } if (!ace_count) return sd; /* No inheritance */ /* Fill in the security descriptor so that it is compatible with our DACL */ user = (const SID *)(parent_sd + 1); group = (const SID *)((char *)(parent_sd + 1) + parent_sd->owner_len); sd = mem_alloc( sizeof(struct security_descriptor) + parent_sd->owner_len + parent_sd->group_len + dacl_size ); if (!sd) return sd; sd->control = SE_DACL_PRESENT; sd->owner_len = parent_sd->owner_len; sd->group_len = parent_sd->group_len; sd->sacl_len = 0; sd->dacl_len = dacl_size; ptr = (char *)(sd + 1); memcpy( ptr, user, sd->owner_len ); ptr += sd->owner_len; memcpy( ptr, group, sd->group_len ); ptr += sd->group_len; dacl = (ACL *)ptr; dacl->AclRevision = ACL_REVISION; dacl->Sbz1 = 0; dacl->AclSize = dacl_size; dacl->AceCount = ace_count; dacl->Sbz2 = 0; ace = (ACE_HEADER *)(dacl + 1); /* Build the new DACL, inheriting from the parent's information */ parent_ace = (const ACE_HEADER *)(parent_dacl + 1); for (i = 0; i < parent_dacl->AceCount; i++, parent_ace = ace_next( parent_ace )) { DWORD flags = parent_ace->AceFlags; if (!(flags & inheritance_mask)) continue; ace->AceType = parent_ace->AceType; if (is_dir && (flags & CONTAINER_INHERIT_ACE)) flags &= ~INHERIT_ONLY_ACE; else if (!is_dir && (flags & OBJECT_INHERIT_ACE)) flags &= ~INHERIT_ONLY_ACE; else if (is_dir && (flags & OBJECT_INHERIT_ACE)) flags |= INHERIT_ONLY_ACE; if (is_dir) ace->AceFlags = flags | INHERITED_ACE; else ace->AceFlags = (parent_ace->AceFlags & ~inheritance_mask) | INHERITED_ACE; ace->AceSize = parent_ace->AceSize; memcpy( ace + 1, parent_ace + 1, parent_ace->AceSize - sizeof(ACE_HEADER)); ace = (ACE_HEADER *)ace_next( ace ); } } return sd; }