void set_xattr_sd( int fd, const struct security_descriptor *sd, const SID *user, const SID *group ) { char buffer[XATTR_SIZE_MAX], *dst_ptr = &buffer[2], *src_ptr = (char *)sd; int present, len, owner_len, group_len; struct security_descriptor *dst_sd; const ACL *dacl; /* there's no point in storing the security descriptor if there's no DACL */ if (!sd) return; dacl = sd_get_dacl( sd, &present ); if (!present || !dacl) return; /* make sure that we always store the ownership information */ if (!sd->owner_len) owner_len = FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]); else owner_len = sd->owner_len; if (!sd->group_len) group_len = FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]); else group_len = sd->group_len; len = 2 + sizeof(struct security_descriptor) + owner_len + group_len + sd->sacl_len + sd->dacl_len; if (len > XATTR_SIZE_MAX) return; /* include the descriptor revision and resource manager control bits */ buffer[0] = SECURITY_DESCRIPTOR_REVISION; buffer[1] = 0; memcpy( dst_ptr, sd, sizeof(struct security_descriptor) ); dst_sd = (struct security_descriptor *)dst_ptr; dst_sd->owner_len = owner_len; dst_sd->group_len = group_len; src_ptr += sizeof(struct security_descriptor); dst_ptr += sizeof(struct security_descriptor); /* copy the appropriate ownership information (explicit or inferred) */ if (sd->owner_len) { memcpy( dst_ptr, src_ptr, sd->owner_len ); src_ptr += sd->owner_len; } else memcpy( dst_ptr, user, owner_len ); dst_ptr += owner_len; if (sd->group_len) { memcpy( dst_ptr, src_ptr, sd->group_len ); src_ptr += sd->group_len; } else memcpy( dst_ptr, group, group_len ); dst_ptr += group_len; /* copy the ACL information (explicit only) */ memcpy( dst_ptr, src_ptr, sd->sacl_len ); src_ptr += sd->sacl_len; dst_ptr += sd->sacl_len; memcpy( dst_ptr, src_ptr, sd->dacl_len ); src_ptr += sd->dacl_len; dst_ptr += sd->dacl_len; xattr_fset( fd, WINE_XATTR_SD, buffer, len ); }
/* 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 *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; }