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; }
static struct object *create_file( struct fd *root, const char *nameptr, data_size_t len, unsigned int access, unsigned int sharing, int create, unsigned int options, unsigned int attrs, const struct security_descriptor *sd ) { struct object *obj = NULL; struct fd *fd; int flags; char *name; mode_t mode; if (!len || ((nameptr[0] == '/') ^ !root)) { set_error( STATUS_OBJECT_PATH_SYNTAX_BAD ); return NULL; } if (!(name = mem_alloc( len + 1 ))) return NULL; memcpy( name, nameptr, len ); name[len] = 0; switch(create) { case FILE_CREATE: flags = O_CREAT | O_EXCL; break; case FILE_OVERWRITE_IF: /* FIXME: the difference is whether we trash existing attr or not */ access |= FILE_WRITE_ATTRIBUTES; case FILE_SUPERSEDE: flags = O_CREAT | O_TRUNC; break; case FILE_OPEN: flags = 0; break; case FILE_OPEN_IF: flags = O_CREAT; break; case FILE_OVERWRITE: flags = O_TRUNC; access |= FILE_WRITE_ATTRIBUTES; break; default: set_error( STATUS_INVALID_PARAMETER ); goto done; } if (sd) { const SID *owner = sd_get_owner( sd ); if (!owner) owner = token_get_user( current->process->token ); mode = sd_to_mode( sd, owner ); } else if (options & FILE_DIRECTORY_FILE) mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0555 : 0777; else mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666; if (len >= 4 && (!strcasecmp( name + len - 4, ".exe" ) || !strcasecmp( name + len - 4, ".com" ))) { if (mode & S_IRUSR) mode |= S_IXUSR; if (mode & S_IRGRP) mode |= S_IXGRP; if (mode & S_IROTH) mode |= S_IXOTH; } access = generic_file_map_access( access ); /* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */ fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options ); if (!fd) goto done; if (S_ISDIR(mode)) obj = create_dir_obj( fd, access, mode ); else if (S_ISCHR(mode) && is_serial_fd( fd )) obj = create_serial( fd ); else obj = create_file_obj( fd, access, mode ); release_object( fd ); done: free( name ); return obj; }
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; }