static struct security_descriptor *file_get_sd( struct object *obj ) { struct file *file = (struct file *)obj; struct stat st; int unix_fd; struct security_descriptor *sd; assert( obj->ops == &file_ops ); unix_fd = get_file_unix_fd( file ); if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return obj->sd; /* mode and uid the same? if so, no need to re-generate security descriptor */ if (obj->sd && (st.st_mode & (S_IRWXU|S_IRWXO)) == (file->mode & (S_IRWXU|S_IRWXO)) && (st.st_uid == file->uid)) return obj->sd; sd = mode_to_sd( st.st_mode, security_unix_uid_to_sid( st.st_uid ), token_get_primary_group( current->process->token )); if (!sd) return obj->sd; file->mode = st.st_mode; file->uid = st.st_uid; free( obj->sd ); obj->sd = sd; return sd; }
/* get the size of the unix file associated with the mapping */ inline static int get_file_size( struct file *file, file_pos_t *size ) { struct stat st; int unix_fd = get_file_unix_fd( file ); if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 0; *size = st.st_size; return 1; }
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; }
/* try to grow the file to the specified size */ int grow_file( struct file *file, file_pos_t size ) { struct stat st; int unix_fd = get_file_unix_fd( file ); if (unix_fd == -1) return 0; if (fstat( unix_fd, &st ) == -1) { file_set_error(); return 0; } if (st.st_size >= size) return 1; /* already large enough */ return extend_file( file, size ); }
/* extend a file beyond the current end of file */ static int extend_file( struct file *file, file_pos_t new_size ) { static const char zero; int unix_fd = get_file_unix_fd( file ); off_t size = new_size; if (unix_fd == -1) return 0; if (sizeof(new_size) > sizeof(size) && size != new_size) { set_error( STATUS_INVALID_PARAMETER ); return 0; } /* extend the file one byte beyond the requested size and then truncate it */ /* this should work around ftruncate implementations that can't extend files */ if (pwrite( unix_fd, &zero, 1, size ) != -1) { ftruncate( unix_fd, size ); return 1; } file_set_error(); return 0; }
/* allocate and fill the temp file for a shared PE image mapping */ static int build_shared_mapping( struct mapping *mapping, int fd, IMAGE_SECTION_HEADER *sec, unsigned int nb_sec ) { unsigned int i, size, max_size, total_size; off_t shared_pos, read_pos, write_pos; char *buffer = NULL; int shared_fd; long toread; /* compute the total size of the shared mapping */ total_size = max_size = 0; for (i = 0; i < nb_sec; i++) { if ((sec[i].Characteristics & IMAGE_SCN_MEM_SHARED) && (sec[i].Characteristics & IMAGE_SCN_MEM_WRITE)) { size = get_section_filemap_size( &sec[i] ); if (size > max_size) max_size = size; total_size += get_section_map_size( &sec[i] ); } } if (!(mapping->shared_size = total_size)) return 1; /* nothing to do */ if ((mapping->shared_file = get_shared_file( mapping ))) return 1; /* create a temp file for the mapping */ if (!(mapping->shared_file = create_temp_file( FILE_GENERIC_READ|FILE_GENERIC_WRITE ))) return 0; if (!grow_file( mapping->shared_file, total_size )) goto error; if ((shared_fd = get_file_unix_fd( mapping->shared_file )) == -1) goto error; if (!(buffer = malloc( max_size ))) goto error; /* copy the shared sections data into the temp file */ shared_pos = 0; for (i = 0; i < nb_sec; i++) { if (!(sec[i].Characteristics & IMAGE_SCN_MEM_SHARED)) continue; if (!(sec[i].Characteristics & IMAGE_SCN_MEM_WRITE)) continue; write_pos = shared_pos; shared_pos += get_section_map_size( &sec[i] ); read_pos = sec[i].PointerToRawData; size = get_section_filemap_size( &sec[i] ); if (!read_pos || !size) continue; toread = size; while (toread) { long res = pread( fd, buffer + sec[i].SizeOfRawData - toread, toread, read_pos ); if (res <= 0) goto error; toread -= res; read_pos += res; } if (pwrite( shared_fd, buffer, size, write_pos ) != size) goto error; } free( buffer ); return 1; error: release_object( mapping->shared_file ); mapping->shared_file = NULL; if (buffer) free( buffer ); return 0; }