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; }
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; }