static int file_set_sd( struct object *obj, const struct security_descriptor *sd, unsigned int set_info ) { struct file *file = (struct file *)obj; const SID *owner; struct stat st; mode_t mode; int unix_fd; assert( obj->ops == &file_ops ); unix_fd = get_file_unix_fd( file ); if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1; if (set_info & OWNER_SECURITY_INFORMATION) { owner = sd_get_owner( sd ); if (!owner) { set_error( STATUS_INVALID_SECURITY_DESCR ); return 0; } if (!obj->sd || !security_equal_sid( owner, sd_get_owner( obj->sd ) )) { /* FIXME: get Unix uid and call fchown */ } } else if (obj->sd) owner = sd_get_owner( obj->sd ); else owner = token_get_user( current->process->token ); /* group and sacl not supported */ if (set_info & DACL_SECURITY_INFORMATION) { /* keep the bits that we don't map to access rights in the ACL */ mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX); mode |= sd_to_mode( sd, owner ); if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1) { file_set_error(); return 0; } } return 1; }
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; }
int set_file_sd( struct object *obj, struct fd *fd, const struct security_descriptor *sd, unsigned int set_info ) { struct security_descriptor *tmp_sd = NULL; int unix_fd = get_unix_fd( fd ); const SID *owner, *group; struct stat st; mode_t mode; int ret = 1; if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1; if (!(set_info & PROTECTED_DACL_SECURITY_INFORMATION)) { char *child_name = fd_get_unix_name( fd ); if (child_name) { struct security_descriptor *parent_sd; parent_sd = file_get_parent_sd( NULL, child_name, strlen(child_name), S_ISDIR(st.st_mode) ); free( child_name ); if (parent_sd) { tmp_sd = file_combine_sds( parent_sd, sd ); if (tmp_sd) sd = tmp_sd; /* only used combined sd if successful */ free( parent_sd ); } } } if (set_info & OWNER_SECURITY_INFORMATION) { owner = sd_get_owner( sd ); if (!owner) { set_error( STATUS_INVALID_SECURITY_DESCR ); ret = 0; goto err; } if (!obj->sd || !security_equal_sid( owner, sd_get_owner( obj->sd ) )) { /* FIXME: get Unix uid and call fchown */ } } else if (obj->sd) owner = sd_get_owner( obj->sd ); else owner = token_get_user( current->process->token ); if (set_info & GROUP_SECURITY_INFORMATION) { group = sd_get_group( sd ); if (!group) { set_error( STATUS_INVALID_SECURITY_DESCR ); ret = 0; goto err; } if (!obj->sd || !security_equal_sid( group, sd_get_group( obj->sd ) )) { /* FIXME: get Unix uid and call fchown */ } } else if (obj->sd) group = sd_get_group( obj->sd ); else group = token_get_primary_group( current->process->token ); /* group and sacl not supported */ if (set_info & DACL_SECURITY_INFORMATION) { /* keep the bits that we don't map to access rights in the ACL */ mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX); mode |= sd_to_mode( sd, owner ); set_xattr_sd( unix_fd, sd, owner, group ); if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1) { file_set_error(); ret = 0; } } err: free( tmp_sd ); return ret; }