diff --git a/src/nfs/nfs_common.h b/src/nfs/nfs_common.h index dc717831..3d5ea192 100644 --- a/src/nfs/nfs_common.h +++ b/src/nfs/nfs_common.h @@ -12,7 +12,6 @@ void nfs_kv_procs(nfs_client_t *self); int nfs3_fsstat_proc(void *opaque, rpc_op_t *rop); int nfs3_fsinfo_proc(void *opaque, rpc_op_t *rop); int nfs3_pathconf_proc(void *opaque, rpc_op_t *rop); -int nfs3_access_proc(void *opaque, rpc_op_t *rop); int nfs3_null_proc(void *opaque, rpc_op_t *rop); int nfs3_commit_proc(void *opaque, rpc_op_t *rop); int mount3_mnt_proc(void *opaque, rpc_op_t *rop); diff --git a/src/nfs/nfs_kv.cpp b/src/nfs/nfs_kv.cpp index dc0b58c7..842d45ba 100644 --- a/src/nfs/nfs_kv.cpp +++ b/src/nfs/nfs_kv.cpp @@ -182,7 +182,7 @@ void nfs_kv_procs(nfs_client_t *self) {NFS_PROGRAM, NFS_V3, NFS3_GETATTR, kv_nfs3_getattr_proc, (xdrproc_t)xdr_GETATTR3args, sizeof(GETATTR3args), (xdrproc_t)xdr_GETATTR3res, sizeof(GETATTR3res), self}, {NFS_PROGRAM, NFS_V3, NFS3_SETATTR, kv_nfs3_setattr_proc, (xdrproc_t)xdr_SETATTR3args, sizeof(SETATTR3args), (xdrproc_t)xdr_SETATTR3res, sizeof(SETATTR3res), self}, {NFS_PROGRAM, NFS_V3, NFS3_LOOKUP, kv_nfs3_lookup_proc, (xdrproc_t)xdr_LOOKUP3args, sizeof(LOOKUP3args), (xdrproc_t)xdr_LOOKUP3res, sizeof(LOOKUP3res), self}, - {NFS_PROGRAM, NFS_V3, NFS3_ACCESS, nfs3_access_proc, (xdrproc_t)xdr_ACCESS3args, sizeof(ACCESS3args), (xdrproc_t)xdr_ACCESS3res, sizeof(ACCESS3res), self}, + {NFS_PROGRAM, NFS_V3, NFS3_ACCESS, kv_nfs3_access_proc, (xdrproc_t)xdr_ACCESS3args, sizeof(ACCESS3args), (xdrproc_t)xdr_ACCESS3res, sizeof(ACCESS3res), self}, {NFS_PROGRAM, NFS_V3, NFS3_READLINK, kv_nfs3_readlink_proc, (xdrproc_t)xdr_READLINK3args, sizeof(READLINK3args), (xdrproc_t)xdr_READLINK3res, sizeof(READLINK3res), self}, {NFS_PROGRAM, NFS_V3, NFS3_READ, kv_nfs3_read_proc, (xdrproc_t)xdr_READ3args, sizeof(READ3args), (xdrproc_t)xdr_READ3res, sizeof(READ3res), self}, {NFS_PROGRAM, NFS_V3, NFS3_WRITE, kv_nfs3_write_proc, (xdrproc_t)xdr_WRITE3args, sizeof(WRITE3args), (xdrproc_t)xdr_WRITE3res, sizeof(WRITE3res), self}, diff --git a/src/nfs/nfs_kv.h b/src/nfs/nfs_kv.h index c569c84a..9261d12f 100644 --- a/src/nfs/nfs_kv.h +++ b/src/nfs/nfs_kv.h @@ -135,7 +135,10 @@ uint64_t align_shared_size(nfs_client_t *self, uint64_t size); void nfs_do_rmw(nfs_rmw_t *rmw); void nfs_move_inode_from(nfs_proxy_t *proxy, uint64_t ino, uint64_t shared_ino, uint64_t shared_offset, std::function cb); +uint32_t kv_get_access(const authsys_parms & auth_sys, const json11::Json & attrs); +bool kv_is_accessible(const authsys_parms & auth_sys, const json11::Json & attrs, uint32_t access); +int kv_nfs3_access_proc(void *opaque, rpc_op_t *rop); int kv_nfs3_getattr_proc(void *opaque, rpc_op_t *rop); int kv_nfs3_setattr_proc(void *opaque, rpc_op_t *rop); int kv_nfs3_lookup_proc(void *opaque, rpc_op_t *rop); diff --git a/src/nfs/nfs_kv_create.cpp b/src/nfs/nfs_kv_create.cpp index c39b98dd..39290413 100644 --- a/src/nfs/nfs_kv_create.cpp +++ b/src/nfs/nfs_kv_create.cpp @@ -111,6 +111,7 @@ static void kv_continue_create(kv_create_state *st, int state) else if (state == 3) goto resume_3; else if (state == 4) goto resume_4; else if (state == 5) goto resume_5; + else if (state == 6) goto resume_6; if (st->self->parent->trace) fprintf(stderr, "[%d] CREATE %ju/%s ATTRS %s\n", st->self->nfs_fd, st->dir_ino, st->filename.c_str(), json11::Json(st->attrobj).dump().c_str()); if (st->filename == "" || st->filename.find("/") != std::string::npos) @@ -127,6 +128,24 @@ static void kv_continue_create(kv_create_state *st, int state) if (st->rop->auth_sys.gid && st->attrobj.find("gid") == st->attrobj.end()) st->attrobj["gid"] = (uint64_t)st->rop->auth_sys.gid; st->attrs = std::move(st->attrobj); + if (st->self->parent->enforce_perms) + { + // Check that the directory is actually a directory and is accessible + kv_read_inode(st->self->parent, st->dir_ino, [st](int res, const std::string & value, json11::Json attrs) + { + st->res = res == 0 ? (attrs["type"].string_value() == "dir" + ? (kv_is_accessible(st->rop->auth_sys, attrs, ACCESS3_MODIFY) ? 0 : -EACCES) : -ENOTDIR) : res; + kv_continue_create(st, 6); + }, true/*allow_cache*/); + return; +resume_6: + if (st->res < 0) + { + auto cb = std::move(st->cb); + cb(st->res); + return; + } + } resume_1: // Generate inode ID // Directories and special files don't need pool diff --git a/src/nfs/nfs_kv_getattr.cpp b/src/nfs/nfs_kv_getattr.cpp index f9da64a8..a28399b6 100644 --- a/src/nfs/nfs_kv_getattr.cpp +++ b/src/nfs/nfs_kv_getattr.cpp @@ -65,6 +65,11 @@ int kv_nfs3_getattr_proc(void *opaque, rpc_op_t *rop) { if (self->parent->trace) fprintf(stderr, "[%d] GETATTR %ju -> %s\n", self->nfs_fd, ino, value.c_str()); + if (res == 0 && self->parent->enforce_perms && + !kv_is_accessible(rop->auth_sys, attrs, ACCESS3_READ)) + { + res = -EACCES; + } if (res < 0) { *reply = (GETATTR3res){ .status = vitastor_nfs_map_err(-res) }; @@ -82,3 +87,101 @@ int kv_nfs3_getattr_proc(void *opaque, rpc_op_t *rop) }); return 1; } + +uint32_t kv_get_access(const authsys_parms & auth_sys, const json11::Json & attrs) +{ + uint32_t mode = attrs["mode"].is_null() ? (attrs["type"] == "dir" ? 0755 : 0644) : attrs["mode"].uint64_value(); + uint32_t uid = attrs["uid"].uint64_value(); + uint32_t gid = attrs["gid"].uint64_value(); + uint32_t access = 0; + if (uid == auth_sys.uid) + { + access |= ((mode & (1 << 8)) ? ACCESS3_READ|ACCESS3_LOOKUP : 0); + access |= ((mode & (1 << 7)) ? ACCESS3_MODIFY|ACCESS3_EXTEND|ACCESS3_DELETE : 0); + access |= ((mode & (1 << 6)) ? ACCESS3_EXECUTE : 0); + } + for (uint32_t i = 0; i < auth_sys.gids.gids_len; i++) + { + if (gid == auth_sys.gids.gids_val[i]) + gid = auth_sys.gid; + } + if (gid == auth_sys.gid) + { + access |= ((mode & (1 << 5)) ? ACCESS3_READ|ACCESS3_LOOKUP : 0); + access |= ((mode & (1 << 4)) ? ACCESS3_MODIFY|ACCESS3_EXTEND|ACCESS3_DELETE : 0); + access |= ((mode & (1 << 3)) ? ACCESS3_EXECUTE : 0); + } + access |= ((mode & (1 << 2)) ? ACCESS3_READ|ACCESS3_LOOKUP : 0); + access |= ((mode & (1 << 1)) ? ACCESS3_MODIFY|ACCESS3_EXTEND|ACCESS3_DELETE : 0); + access |= ((mode & (1 << 0)) ? ACCESS3_EXECUTE : 0); + return access; +} + +bool kv_is_accessible(const authsys_parms & auth_sys, const json11::Json & attrs, uint32_t access) +{ + uint32_t mode = attrs["mode"].is_null() ? (attrs["type"] == "dir" ? 0755 : 0644) : attrs["mode"].uint64_value(); + uint32_t mask = 1 << (access == ACCESS3_EXECUTE ? 0 + : (access == ACCESS3_MODIFY || access == ACCESS3_EXTEND || access == ACCESS3_DELETE ? 1 : 2)); + if (mode & mask) + return true; + uint32_t uid = attrs["uid"].uint64_value(); + if ((mode & (mask << 6)) && (uint32_t)uid == auth_sys.uid) + return true; + if ((mode & (mask << 3))) + { + uint32_t gid = attrs["gid"].uint64_value(); + if (gid == auth_sys.gid) + return true; + for (uint32_t i = 0; i < auth_sys.gids.gids_len; i++) + if (gid == auth_sys.gids.gids_val[i]) + return true; + } + return false; +} + +int kv_nfs3_access_proc(void *opaque, rpc_op_t *rop) +{ + nfs_client_t *self = (nfs_client_t*)opaque; + ACCESS3args *args = (ACCESS3args*)rop->request; + ACCESS3res *reply = (ACCESS3res*)rop->reply; + std::string fh = args->object; + auto ino = kv_fh_inode(fh); + if (self->parent->trace) + fprintf(stderr, "[%d] ACCESS %ju\n", self->nfs_fd, ino); + if (!kv_fh_valid(fh) || !ino) + { + *reply = (ACCESS3res){ .status = NFS3ERR_INVAL }; + rpc_queue_reply(rop); + return 0; + } + kv_read_inode(self->parent, ino, [=](int res, const std::string & value, json11::Json attrs) + { + if (self->parent->trace) + fprintf(stderr, "[%d] ACCESS %ju -> %s\n", self->nfs_fd, ino, value.c_str()); + if (res < 0) + { + *reply = (ACCESS3res){ .status = vitastor_nfs_map_err(-res) }; + } + else + { + uint32_t actual = kv_get_access(rop->auth_sys, attrs); + if (args->access & actual) + { + *reply = (ACCESS3res){ + .status = NFS3_OK, + .resok = (ACCESS3resok){ + .access = actual, + }, + }; + } + else + { + *reply = (ACCESS3res){ + .status = NFS3ERR_ACCES, + }; + } + } + rpc_queue_reply(rop); + }); + return 1; +} diff --git a/src/nfs/nfs_kv_link.cpp b/src/nfs/nfs_kv_link.cpp index 93690951..c126b2fd 100644 --- a/src/nfs/nfs_kv_link.cpp +++ b/src/nfs/nfs_kv_link.cpp @@ -49,7 +49,8 @@ resume_0: st->res2 = 0; kv_read_inode(st->self->parent, st->ino, [st](int res, const std::string & value, json11::Json attrs) { - st->res = res == 0 ? (attrs["type"].string_value() == "dir" ? -EISDIR : 0) : res; + st->res = (res != 0 ? res : (attrs["type"].string_value() == "dir" ? -EISDIR : + (st->self->parent->enforce_perms && !kv_is_accessible(st->rop->auth_sys, attrs, ACCESS3_READ) ? -EACCES : 0))); st->ientry_text = value; st->ientry = attrs; if (!--st->wait) @@ -60,7 +61,8 @@ resume_0: // Check that the new directory exists kv_read_inode(st->self->parent, st->dir_ino, [st](int res, const std::string & value, json11::Json attrs) { - st->res2 = res == 0 ? (attrs["type"].string_value() == "dir" ? 0 : -ENOTDIR) : res; + st->res2 = (res != 0 ? res : (attrs["type"].string_value() != "dir" ? -ENOTDIR : + (st->self->parent->enforce_perms && !kv_is_accessible(st->rop->auth_sys, attrs, ACCESS3_MODIFY) ? -EACCES : 0))); if (!--st->wait) nfs_kv_continue_link(st, 1); }); diff --git a/src/nfs/nfs_kv_lookup.cpp b/src/nfs/nfs_kv_lookup.cpp index 07b9d8eb..81403e41 100644 --- a/src/nfs/nfs_kv_lookup.cpp +++ b/src/nfs/nfs_kv_lookup.cpp @@ -70,6 +70,13 @@ int kv_nfs3_lookup_proc(void *opaque, rpc_op_t *rop) rpc_queue_reply(rop); return; } + else if (self->parent->enforce_perms && ientry["type"] != "link" && + !kv_is_accessible(rop->auth_sys, ientry, ACCESS3_LOOKUP)) + { + *reply = (LOOKUP3res){ .status = NFS3ERR_ACCES }; + rpc_queue_reply(rop); + return; + } *reply = (LOOKUP3res){ .status = NFS3_OK, .resok = (LOOKUP3resok){ diff --git a/src/nfs/nfs_kv_read.cpp b/src/nfs/nfs_kv_read.cpp index 16ee4d4e..1b34b10c 100644 --- a/src/nfs/nfs_kv_read.cpp +++ b/src/nfs/nfs_kv_read.cpp @@ -66,6 +66,12 @@ resume_1: cb(st->res < 0 ? st->res : -EINVAL); return; } + if (st->self->parent->enforce_perms && !kv_is_accessible(st->rop->auth_sys, st->ientry, ACCESS3_READ)) + { + auto cb = std::move(st->cb); + cb(-EACCES); + return; + } if (st->ientry["shared_ino"].uint64_value() != 0) { if (st->offset >= st->ientry["size"].uint64_value()) @@ -142,9 +148,9 @@ resume_2: return; } } - else if (st->self->rdma_conn) + else if (st->self->rdma_conn || st->self->parent->enforce_perms) { - // Take ientry from read_hack_cache for RDMA connections + // Take ientry from read_hack_cache for RDMA connections or for the permission check { auto rh_it = st->self->parent->kvfs->read_hack_cache.find(st->ino); if (rh_it != st->self->parent->kvfs->read_hack_cache.end()) @@ -170,6 +176,12 @@ resume_4: } st->self->parent->kvfs->read_hack_cache[st->ino] = st->ientry; } + if (st->self->parent->enforce_perms && !kv_is_accessible(st->rop->auth_sys, st->ientry, ACCESS3_READ)) + { + auto cb = std::move(st->cb); + cb(-EACCES); + return; + } } st->aligned_offset = align_down(st->offset); st->aligned_size = align_up(st->offset+st->size) - st->aligned_offset; diff --git a/src/nfs/nfs_kv_readdir.cpp b/src/nfs/nfs_kv_readdir.cpp index 1723eccf..2ad1c12f 100644 --- a/src/nfs/nfs_kv_readdir.cpp +++ b/src/nfs/nfs_kv_readdir.cpp @@ -94,7 +94,7 @@ static void nfs_kv_continue_readdir(nfs_kv_readdir_state *st, int state) return; } // Add . and .. - if (st->cookie <= 1) + if (st->cookie <= 1 || st->self->parent->enforce_perms) { kv_read_inode(st->self->parent, st->dir_ino, [st](int res, const std::string & value, json11::Json ientry) { @@ -111,6 +111,15 @@ resume_1: cb(st->res); return; } + if (st->self->parent->enforce_perms && !kv_is_accessible(st->rop->auth_sys, st->ientry, ACCESS3_READ)) + { + auto cb = std::move(st->cb); + cb(-EACCES); + return; + } + } + if (st->cookie <= 1) + { if (st->cookie == 0) { auto fh = kv_fh(st->dir_ino); diff --git a/src/nfs/nfs_kv_remove.cpp b/src/nfs/nfs_kv_remove.cpp index 6e8f73b7..7b4ab368 100644 --- a/src/nfs/nfs_kv_remove.cpp +++ b/src/nfs/nfs_kv_remove.cpp @@ -44,6 +44,7 @@ static void nfs_kv_continue_delete(kv_del_state *st, int state) else if (state == 5) goto resume_5; else if (state == 6) goto resume_6; else if (state == 7) goto resume_7; + else if (state == 8) goto resume_8; else { fprintf(stderr, "BUG: invalid state in nfs_kv_continue_delete()"); @@ -123,6 +124,28 @@ resume_2: cb(st->is_rmdir ? -ENOTDIR : -EISDIR); return; } + if (st->self->parent->enforce_perms) + { + // Check directory permission + kv_read_inode(st->self->parent, st->dir_ino, [st](int res, const std::string & value, json11::Json attrs) + { + st->res = (res != 0 ? res : (attrs["type"].string_value() != "dir" ? -ENOTDIR : + (st->self->parent->enforce_perms && ( + !kv_is_accessible(st->rop->auth_sys, attrs, ACCESS3_DELETE) && + (!(attrs["mode"].uint64_value() & 01000 /* directory sticky bit */) || + st->ientry["uid"].uint64_value() != st->rop->auth_sys.uid) + ) ? -EACCES : 0))); + nfs_kv_continue_delete(st, 8); + }, st->allow_cache); + return; +resume_8: + if (st->res < 0) + { + auto cb = std::move(st->cb); + cb(st->res); + return; + } + } // (3) Delete direntry with CAS st->self->parent->db->del(kv_direntry_key(st->dir_ino, st->filename), [st](int res) { @@ -157,7 +180,7 @@ resume_3: } if (st->is_rmdir) { - // (4) Check if directory actually is not empty + // (4) Check if the directory actually is not empty st->list_handle = st->self->parent->db->list_start(kv_direntry_key(st->ino, "")); st->self->parent->db->list_next(st->list_handle, [st](int res, const std::string & key, const std::string & value) { diff --git a/src/nfs/nfs_kv_rename.cpp b/src/nfs/nfs_kv_rename.cpp index ce4fe570..72b6236b 100644 --- a/src/nfs/nfs_kv_rename.cpp +++ b/src/nfs/nfs_kv_rename.cpp @@ -60,6 +60,7 @@ static void nfs_kv_continue_rename(nfs_kv_rename_state *st, int state) else if (state == 10) goto resume_10; else if (state == 11) goto resume_11; else if (state == 12) goto resume_12; + else if (state == 13) goto resume_13; else { fprintf(stderr, "BUG: invalid state in nfs_kv_continue_rename()"); @@ -154,12 +155,13 @@ resume_3: } } } - else + if (!st->new_exists || st->self->parent->enforce_perms) { // Check that the new directory is actually a directory kv_read_inode(st->self->parent, st->new_dir_ino, [st](int res, const std::string & value, json11::Json attrs) { - st->res = res == 0 ? (attrs["type"].string_value() == "dir" ? 0 : -ENOTDIR) : res; + st->res = (res != 0 ? res : (attrs["type"].string_value() != "dir" ? -ENOTDIR : + (st->self->parent->enforce_perms && !kv_is_accessible(st->rop->auth_sys, attrs, ACCESS3_MODIFY) ? -EACCES : 0))); nfs_kv_continue_rename(st, 4); }); return; @@ -171,6 +173,24 @@ resume_4: return; } } + if (st->self->parent->enforce_perms) + { + // Check that the old directory is accessible + kv_read_inode(st->self->parent, st->old_dir_ino, [st](int res, const std::string & value, json11::Json attrs) + { + st->res = (res != 0 ? res : (attrs["type"].string_value() != "dir" ? -ENOTDIR : + (!kv_is_accessible(st->rop->auth_sys, attrs, ACCESS3_MODIFY) ? -EACCES : 0))); + nfs_kv_continue_rename(st, 13); + }); + return; +resume_13: + if (st->res < 0) + { + auto cb = std::move(st->cb); + cb(st->res); + return; + } + } // Write the new direntry st->self->parent->db->set(kv_direntry_key(st->new_dir_ino, st->new_name), st->old_direntry_text, [st](int res) { diff --git a/src/nfs/nfs_kv_setattr.cpp b/src/nfs/nfs_kv_setattr.cpp index 20cfa61f..b55b3c73 100644 --- a/src/nfs/nfs_kv_setattr.cpp +++ b/src/nfs/nfs_kv_setattr.cpp @@ -53,6 +53,12 @@ resume_1: cb(st->res); return; } + if (st->self->parent->enforce_perms && !kv_is_accessible(st->rop->auth_sys, st->ientry, ACCESS3_MODIFY)) + { + auto cb = std::move(st->cb); + cb(-EACCES); + return; + } if (st->ientry["type"].string_value() != "file" && st->ientry["type"].string_value() != "" && !st->set_attrs["size"].is_null()) diff --git a/src/nfs/nfs_kv_write.cpp b/src/nfs/nfs_kv_write.cpp index 17427f27..1513817e 100644 --- a/src/nfs/nfs_kv_write.cpp +++ b/src/nfs/nfs_kv_write.cpp @@ -786,6 +786,12 @@ resume_1: cb(st->res == 0 ? -EINVAL : st->res); return; } + if (st->proxy->enforce_perms && !kv_is_accessible(st->rop->auth_sys, st->ientry, ACCESS3_MODIFY)) + { + auto cb = std::move(st->cb); + cb(-EACCES); + return; + } st->was_immediate = st->proxy->cli->get_immediate_commit(st->ino); st->new_size = st->ientry["size"].uint64_value(); if (st->new_size < st->offset + st->size) diff --git a/src/nfs/nfs_mount.cpp b/src/nfs/nfs_mount.cpp index 5c94ac3d..2d7c3198 100644 --- a/src/nfs/nfs_mount.cpp +++ b/src/nfs/nfs_mount.cpp @@ -16,12 +16,13 @@ nfsstat3 vitastor_nfs_map_err(int err) } return (err == EINVAL ? NFS3ERR_INVAL : (err == ENOENT ? NFS3ERR_NOENT + : (err == EACCES ? NFS3ERR_ACCES : (err == ENOSPC ? NFS3ERR_NOSPC : (err == EEXIST ? NFS3ERR_EXIST : (err == EISDIR ? NFS3ERR_ISDIR : (err == ENOTDIR ? NFS3ERR_NOTDIR : (err == ENOTEMPTY ? NFS3ERR_NOTEMPTY - : (err == EIO ? NFS3ERR_IO : (err ? NFS3ERR_IO : NFS3_OK))))))))); + : (err == EIO ? NFS3ERR_IO : (err ? NFS3ERR_IO : NFS3_OK)))))))))); } int nfs3_null_proc(void *opaque, rpc_op_t *rop) @@ -30,21 +31,6 @@ int nfs3_null_proc(void *opaque, rpc_op_t *rop) return 0; } -int nfs3_access_proc(void *opaque, rpc_op_t *rop) -{ - //nfs_client_t *self = (nfs_client_t*)opaque; - ACCESS3args *args = (ACCESS3args*)rop->request; - ACCESS3res *reply = (ACCESS3res*)rop->reply; - *reply = (ACCESS3res){ - .status = NFS3_OK, - .resok = (ACCESS3resok){ - .access = args->access, - }, - }; - rpc_queue_reply(rop); - return 0; -} - int nfs3_commit_proc(void *opaque, rpc_op_t *rop) { nfs_client_t *self = (nfs_client_t*)opaque; diff --git a/src/nfs/nfs_proxy.cpp b/src/nfs/nfs_proxy.cpp index b143af20..e4570cb8 100644 --- a/src/nfs/nfs_proxy.cpp +++ b/src/nfs/nfs_proxy.cpp @@ -119,6 +119,7 @@ static const char* help_text = " --nfspath set NFS export path to (default is /)\n" " --pidfile write process ID to the specified file\n" " --logfile log to the specified file\n" + " --enforce 1 enforce permissions at the server side (default is disabled)\n" " --foreground 1 stay in foreground, do not daemonize\n" "\n" "NFS proxy is stateless if you use immediate_commit=all in your cluster and if\n" @@ -206,6 +207,7 @@ void nfs_proxy_t::run(json11::Json cfg) bind_address = "0.0.0.0"; default_pool = cfg["pool"].as_string(); portmap_enabled = !json_is_false(cfg["portmap"]); + enforce_perms = json_is_true(cfg["enforce"]); nfs_port = cfg["port"].uint64_value() & 0xffff; #ifdef WITH_RDMACM nfs_rdma_port = cfg["nfs_rdma"].uint64_value() & 0xffff; diff --git a/src/nfs/nfs_proxy.h b/src/nfs/nfs_proxy.h index 9a3f662d..8ab8e99e 100644 --- a/src/nfs/nfs_proxy.h +++ b/src/nfs/nfs_proxy.h @@ -33,7 +33,8 @@ public: // FIXME: Maybe allow to create files in different pools? std::string default_pool; std::string export_root; - bool portmap_enabled; + bool enforce_perms = false; + bool portmap_enabled = false; bool nfs_port_auto = false; unsigned nfs_port = 0; unsigned nfs_rdma_port = 0;