fuse permission fixes
This commit is contained in:
parent
bd25904371
commit
841d57cf13
@ -170,6 +170,9 @@ renterd
|
|||||||
richtext
|
richtext
|
||||||
rocksdb_library
|
rocksdb_library
|
||||||
rpcrt4
|
rpcrt4
|
||||||
|
s_igid
|
||||||
|
s_isvtx
|
||||||
|
s_iuid
|
||||||
sddl_revision_1
|
sddl_revision_1
|
||||||
secp256k1
|
secp256k1
|
||||||
secur32
|
secur32
|
||||||
|
@ -67,6 +67,11 @@ auto fuse_drive::chmod_impl(std::string api_path, mode_t mode,
|
|||||||
auto fuse_drive::chmod_impl(std::string api_path, mode_t mode) -> api_error {
|
auto fuse_drive::chmod_impl(std::string api_path, mode_t mode) -> api_error {
|
||||||
#endif // FUSE_USE_VERSION >= 30
|
#endif // FUSE_USE_VERSION >= 30
|
||||||
return check_and_perform(api_path, X_OK, [&](api_meta_map &) -> api_error {
|
return check_and_perform(api_path, X_OK, [&](api_meta_map &) -> api_error {
|
||||||
|
if ((mode & (S_IGID | S_IUID | S_ISVTX) != 0) &&
|
||||||
|
(get_effective_uid() != 0)) {
|
||||||
|
return api_error::permission_denied;
|
||||||
|
}
|
||||||
|
|
||||||
return provider_.set_item_meta(api_path, META_MODE, std::to_string(mode));
|
return provider_.set_item_meta(api_path, META_MODE, std::to_string(mode));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -86,23 +91,24 @@ auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
|
|||||||
if (get_effective_uid() != 0) {
|
if (get_effective_uid() != 0) {
|
||||||
return api_error::permission_denied;
|
return api_error::permission_denied;
|
||||||
}
|
}
|
||||||
|
|
||||||
meta[META_UID] = std::to_string(uid);
|
meta[META_UID] = std::to_string(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gid != static_cast<gid_t>(-1)) {
|
if (gid != static_cast<gid_t>(-1)) {
|
||||||
if (get_effective_uid() != 0) {
|
if (get_effective_uid() != 0 &&
|
||||||
if (not utils::is_uid_member_of_group(get_effective_uid(), gid)) {
|
not utils::is_uid_member_of_group(get_effective_uid(), gid)) {
|
||||||
return api_error::permission_denied;
|
return api_error::permission_denied;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
meta[META_GID] = std::to_string(gid);
|
meta[META_GID] = std::to_string(gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not meta.empty()) {
|
if (meta.empty()) {
|
||||||
return provider_.set_item_meta(api_path, meta);
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
return api_error::success;
|
return provider_.set_item_meta(api_path, meta);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,16 +32,22 @@
|
|||||||
#include "providers/encrypt/encrypt_provider.hpp"
|
#include "providers/encrypt/encrypt_provider.hpp"
|
||||||
#include "providers/s3/s3_provider.hpp"
|
#include "providers/s3/s3_provider.hpp"
|
||||||
#include "providers/sia/sia_provider.hpp"
|
#include "providers/sia/sia_provider.hpp"
|
||||||
|
#include "types/repertory.hpp"
|
||||||
|
#include "utils/event_capture.hpp"
|
||||||
#include "utils/file_utils.hpp"
|
#include "utils/file_utils.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
#if !defined(ACCESSPERMS)
|
#if !defined(ACCESSPERMS)
|
||||||
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) /* 0777 */
|
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) /* 0777 */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace repertory {
|
namespace {
|
||||||
inline constexpr const auto SLEEP_SECONDS{1.5s};
|
std::atomic<std::size_t> idx{0U};
|
||||||
|
constexpr const auto SLEEP_SECONDS{1.5s};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
template <typename provider_t> class fuse_test : public ::testing::Test {
|
template <typename provider_t> class fuse_test : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
static std::string cfg_directory;
|
static std::string cfg_directory;
|
||||||
@ -147,7 +153,10 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static auto create_file_and_test(std::string name) -> std::string {
|
static auto create_file_and_test(std::string name) -> std::string {
|
||||||
auto file_path = utils::path::combine(mount_location, {name});
|
auto file_path =
|
||||||
|
utils::path::combine(mount_location, {
|
||||||
|
name + std::to_string(++idx),
|
||||||
|
});
|
||||||
|
|
||||||
auto fd =
|
auto fd =
|
||||||
open(file_path.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
|
open(file_path.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
|
||||||
@ -166,6 +175,19 @@ public:
|
|||||||
return file_path;
|
return file_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto create_root_file(std::string name) -> std::string {
|
||||||
|
auto file_path = create_file_and_test(name);
|
||||||
|
|
||||||
|
auto api_path =
|
||||||
|
utils::path::create_api_path(utils::path::strip_to_filename(file_path));
|
||||||
|
provider->set_item_meta(api_path, {
|
||||||
|
{META_UID, "0"},
|
||||||
|
{META_GID, "0"},
|
||||||
|
});
|
||||||
|
|
||||||
|
return file_path;
|
||||||
|
}
|
||||||
|
|
||||||
static void execute_mount(auto &&drive_args) {
|
static void execute_mount(auto &&drive_args) {
|
||||||
auto mount_cmd = "./repertory -dd \"" + config->get_data_directory() +
|
auto mount_cmd = "./repertory -dd \"" + config->get_data_directory() +
|
||||||
"\"" + " " + utils::string::join(drive_args, ' ');
|
"\"" + " " + utils::string::join(drive_args, ' ');
|
||||||
@ -200,6 +222,18 @@ public:
|
|||||||
EXPECT_FALSE(utils::file::directory(file_path).exists());
|
EXPECT_FALSE(utils::file::directory(file_path).exists());
|
||||||
EXPECT_FALSE(utils::file::file(file_path).exists());
|
EXPECT_FALSE(utils::file::file(file_path).exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unlink_root_file(const std::string &file_path) {
|
||||||
|
auto api_path =
|
||||||
|
utils::path::create_api_path(utils::path::strip_to_filename(file_path));
|
||||||
|
|
||||||
|
provider->set_item_meta(api_path, {
|
||||||
|
{META_UID, std::to_string(getuid())},
|
||||||
|
{META_GID, std::to_string(getgid())},
|
||||||
|
});
|
||||||
|
|
||||||
|
unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename provider_t>
|
template <typename provider_t>
|
||||||
|
@ -19,22 +19,10 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#if 0
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
|
|
||||||
#include "fixtures/fuse_fixture.hpp"
|
#include "fixtures/fuse_fixture.hpp"
|
||||||
|
|
||||||
// #include "app_config.hpp"
|
|
||||||
// #include "comm/curl/curl_comm.hpp"
|
|
||||||
// #include "drives/fuse/fuse_drive.hpp"
|
|
||||||
// #include "platform/platform.hpp"
|
|
||||||
// #include "providers/s3/s3_provider.hpp"
|
|
||||||
// #include "providers/sia/sia_provider.hpp"
|
|
||||||
// #include "types/repertory.hpp"
|
|
||||||
// #include "utils/event_capture.hpp"
|
|
||||||
// #include "utils/file_utils.hpp"
|
|
||||||
// #include "utils/utils.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
// static void rmdir_and_test(const std::string &directory_path) {
|
// static void rmdir_and_test(const std::string &directory_path) {
|
||||||
// std::cout << __FUNCTION__ << std::endl;
|
// std::cout << __FUNCTION__ << std::endl;
|
||||||
@ -529,7 +517,7 @@ namespace repertory {
|
|||||||
|
|
||||||
TYPED_TEST_CASE(fuse_test, fuse_provider_types);
|
TYPED_TEST_CASE(fuse_test, fuse_provider_types);
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, chmod) {
|
TYPED_TEST(fuse_test, can_chmod_if_owner) {
|
||||||
auto file_path = this->create_file_and_test("chmod_test");
|
auto file_path = this->create_file_and_test("chmod_test");
|
||||||
EXPECT_EQ(0, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
EXPECT_EQ(0, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
||||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||||
@ -538,27 +526,110 @@ TYPED_TEST(fuse_test, chmod) {
|
|||||||
stat64(file_path.c_str(), &unix_st);
|
stat64(file_path.c_str(), &unix_st);
|
||||||
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR),
|
EXPECT_EQ(static_cast<std::uint32_t>(S_IRUSR | S_IWUSR),
|
||||||
ACCESSPERMS & unix_st.st_mode);
|
ACCESSPERMS & unix_st.st_mode);
|
||||||
|
|
||||||
this->unlink_file_and_test(file_path);
|
this->unlink_file_and_test(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, chown) {
|
TYPED_TEST(fuse_test, can_not_chmod_if_not_owner) {
|
||||||
|
auto file_path = this->create_root_file("chmod_test");
|
||||||
|
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
this->unlink_root_file(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chmod_setgid_if_not_root) {
|
||||||
|
auto file_path = this->create_file_and_test("chown_test");
|
||||||
|
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_IGID));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chmod_setuid_if_not_root) {
|
||||||
|
auto file_path = this->create_file_and_test("chown_test");
|
||||||
|
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_IUID));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chmod_set_sticky_if_not_root) {
|
||||||
|
auto file_path = this->create_file_and_test("chown_test");
|
||||||
|
EXPECT_EQ(-1, chmod(file_path.c_str(), S_IRUSR | S_IWUSR | S_ISVTX));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_chown_group_if_owner_and_a_member_of_the_group) {
|
||||||
auto file_path = this->create_file_and_test("chown_test");
|
auto file_path = this->create_file_and_test("chown_test");
|
||||||
EXPECT_EQ(0, chown(file_path.c_str(), static_cast<uid_t>(-1), 0));
|
|
||||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
|
||||||
|
|
||||||
struct stat64 unix_st{};
|
struct stat64 unix_st{};
|
||||||
stat64(file_path.c_str(), &unix_st);
|
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||||
EXPECT_EQ(0U, unix_st.st_gid);
|
|
||||||
|
|
||||||
EXPECT_EQ(0, chown(file_path.c_str(), 0, static_cast<gid_t>(-1)));
|
EXPECT_EQ(0, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
|
||||||
std::this_thread::sleep_for(SLEEP_SECONDS);
|
std::this_thread::sleep_for(SLEEP_SECONDS);
|
||||||
|
|
||||||
stat64(file_path.c_str(), &unix_st);
|
struct stat64 unix_st2{};
|
||||||
EXPECT_EQ(0U, unix_st.st_gid);
|
stat64(file_path.c_str(), &unix_st2);
|
||||||
|
EXPECT_EQ(getgid(), unix_st2.st_gid);
|
||||||
|
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test,
|
||||||
|
can_not_chown_group_if_owner_but_not_a_member_of_the_group) {
|
||||||
|
auto file_path = this->create_file_and_test("chown_test");
|
||||||
|
|
||||||
|
struct stat64 unix_st{};
|
||||||
|
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), 0));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
struct stat64 unix_st2{};
|
||||||
|
stat64(file_path.c_str(), &unix_st2);
|
||||||
|
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
||||||
|
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chown_group_if_not_the_owner) {
|
||||||
|
auto file_path = this->create_root_file("chown_test");
|
||||||
|
|
||||||
|
struct stat64 unix_st{};
|
||||||
|
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chown(file_path.c_str(), static_cast<uid_t>(-1), getgid()));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
struct stat64 unix_st2{};
|
||||||
|
stat64(file_path.c_str(), &unix_st2);
|
||||||
|
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
||||||
|
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||||
|
|
||||||
|
this->unlink_root_file(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_not_chown_user_if_not_root) {
|
||||||
|
auto file_path = this->create_file_and_test("chown_test");
|
||||||
|
|
||||||
|
struct stat64 unix_st{};
|
||||||
|
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, chown(file_path.c_str(), 0, static_cast<gid_t>(-1)));
|
||||||
|
EXPECT_EQ(EPERM, errno);
|
||||||
|
|
||||||
|
struct stat64 unix_st2{};
|
||||||
|
stat64(file_path.c_str(), &unix_st2);
|
||||||
|
EXPECT_EQ(unix_st.st_gid, unix_st2.st_gid);
|
||||||
|
EXPECT_EQ(unix_st.st_uid, unix_st2.st_uid);
|
||||||
|
|
||||||
this->unlink_file_and_test(file_path);
|
this->unlink_file_and_test(file_path);
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // !defined(_WIN32)
|
#endif // !defined(_WIN32)
|
||||||
#endif // 0
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user