diff -r 21274e5950af -r 2160585200ac src/server/daemon/vfs.c --- a/src/server/daemon/vfs.c Tue Aug 13 22:14:32 2019 +0200 +++ b/src/server/daemon/vfs.c Thu Oct 31 10:26:35 2019 +0100 @@ -52,9 +52,11 @@ sys_vfs_stat, sys_vfs_fstat, sys_vfs_opendir, + sys_vfs_fdopendir, sys_vfs_mkdir, sys_vfs_unlink, - VFS_CHECKS_ACL + VFS_CHECKS_ACL, + NULL }; static VFS_IO sys_file_io = { @@ -202,6 +204,27 @@ return dir; } +VFS_DIR vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { + WS_ASSERT(ctx); + WS_ASSERT(path); + + uint32_t access_mask = ctx->aclreqaccess | ACL_LIST; + + // ctx->aclreqaccess should be the complete access mask + uint32_t m = ctx->aclreqaccess; // save original access mask + ctx->aclreqaccess = access_mask; // set mask for vfs->open call + if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { + // VFS does not evaluates the ACL itself, so we have to do it here + SysACL sysacl; + if(sys_acl_check(ctx, access_mask, &sysacl)) { + return NULL; + } + } + VFS_DIR dir = ctx->vfs->fdopendir(ctx, fd); + ctx->aclreqaccess = m; // restore original access mask + return dir; +} + int vfs_readdir(VFS_DIR dir, VFS_ENTRY *entry) { WS_ASSERT(dir); WS_ASSERT(entry); @@ -422,6 +445,62 @@ return dir; } +VFS_DIR sys_vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { + uint32_t access_mask = ctx->aclreqaccess; + pool_handle_t *pool = ctx->pool; + + // check ACLs + SysACL sysacl; + if(sys_acl_check(ctx, access_mask, &sysacl)) { + return NULL; + } + + if(sysacl.acl) { + if(!fs_acl_check_fd(&sysacl, ctx->user, fd->fd, access_mask)) { + acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user); + return NULL; + } + } + + // open directory + DIR *sys_dir = fdopendir(fd->fd); + if(!sys_dir) { + if(ctx) { + ctx->vfs_errno = errno; + sys_set_error_status(ctx); + } + return NULL; + } + + SysVFSDir *dir_data = VFS_MALLOC(pool, sizeof(SysVFSDir)); + if(!dir_data) { + closedir(sys_dir); + return NULL; + } + long maxfilelen = fpathconf(fd->fd, _PC_NAME_MAX); + size_t entry_len = offsetof(struct dirent, d_name) + maxfilelen + 1; + dir_data->cur = VFS_MALLOC(pool, entry_len); + if(!dir_data->cur) { + closedir(sys_dir); + VFS_FREE(pool, dir_data); + return NULL; + } + dir_data->dir = sys_dir; + + VFSDir *dir = VFS_MALLOC(pool, sizeof(VFSDir)); + if(!dir) { + closedir(sys_dir); + VFS_FREE(pool, dir_data->cur); + VFS_FREE(pool, dir_data); + return NULL; + } + dir->ctx = ctx; + dir->data = dir_data; + dir->fd = fd->fd; + dir->io = &sys_dir_io; + return dir; +} + int sys_vfs_mkdir(VFSContext *ctx, char *path) { return sys_path_op(ctx, path, sys_mkdir); } @@ -539,6 +618,7 @@ entry->name = name; if(getstat) { // TODO: check ACLs again for new path + entry->stat_errno = 0; if(fstatat(dir->fd, result->d_name, &entry->stat, 0)) { entry->stat_errno = errno; }