From 817d682de5fa47c1dc7a47981d9dc6d487dc7a65 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 29 Sep 2015 16:25:01 +0800 Subject: [PATCH] client: permission check for creating/deleting files Signed-off-by: Yan, Zheng --- src/client/Client.cc | 125 +++++++++++++++++++++++++++++++++++++++---- src/client/Client.h | 2 + 2 files changed, 116 insertions(+), 11 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index c3ddda64e12df..5701c1f786b2c 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -4889,6 +4889,53 @@ out: return r; } +int Client::may_create(Inode *dir, int uid, int gid) +{ + if (uid < 0) + uid = get_uid(); + if (gid < 0) + gid = get_gid(); + RequestUserGroups groups(this, uid, gid); + + int r = _getattr(dir, CEPH_STAT_CAP_MODE, uid, gid); + if (r < 0) + goto out; + + r = inode_permission(dir, uid, groups, MAY_EXEC | MAY_WRITE); +out: + ldout(cct, 3) << __func__ << " " << dir << " = " << r << dendl; + return r; +} + +int Client::may_delete(Inode *dir, const char *name, int uid, int gid) +{ + if (uid < 0) + uid = get_uid(); + if (gid < 0) + gid = get_gid(); + RequestUserGroups groups(this, uid, gid); + + int r = _getattr(dir, CEPH_STAT_CAP_MODE, uid, gid); + if (r < 0) + goto out; + + r = inode_permission(dir, uid, groups, MAY_EXEC | MAY_WRITE); + if (r < 0) + goto out; + + if (uid != 0 && (dir->mode & S_ISVTX)) { + InodeRef otherin; + r = _lookup(dir, name, &otherin, uid, gid); + if (r < 0) + goto out; + if (dir->uid != (uid_t)uid && otherin->uid != (uid_t)uid) + r = -EPERM; + } +out: + ldout(cct, 3) << __func__ << " " << dir << " = " << r << dendl; + return r; +} + vinodeno_t Client::_get_vino(Inode *in) { /* The caller must hold the client lock */ @@ -5809,11 +5856,11 @@ int Client::mknod(const char *relpath, mode_t mode, dev_t rdev) filepath path(relpath); string name = path.last_dentry(); path.pop_dentry(); - InodeRef in; - int r = path_walk(path, &in); + InodeRef dir; + int r = path_walk(path, &dir); if (r < 0) return r; - return _mknod(in.get(), name.c_str(), mode, rdev); + return _mknod(dir.get(), name.c_str(), mode, rdev); } // symlinks @@ -7053,7 +7100,7 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, InodeRef dir; r = path_walk(dirpath, &dir); if (r < 0) - return r; + goto out; r = _create(dir.get(), dname.c_str(), flags, mode, &in, &fh, stripe_unit, stripe_count, object_size, data_pool, &created); } @@ -9839,6 +9886,12 @@ int Client::ll_mknod(Inode *parent, const char *name, mode_t mode, tout(cct) << mode << std::endl; tout(cct) << rdev << std::endl; + if (!cct->_conf->fuse_default_permissions) { + int r = may_create(parent, uid, gid); + if (r < 0) + return r; + } + InodeRef in; int r = _mknod(parent, name, mode, rdev, uid, gid, &in); if (r == 0) { @@ -10011,6 +10064,12 @@ int Client::ll_mkdir(Inode *parent, const char *name, mode_t mode, tout(cct) << name << std::endl; tout(cct) << mode << std::endl; + if (!cct->_conf->fuse_default_permissions) { + int r = may_create(parent, uid, gid); + if (r < 0) + return r; + } + InodeRef in; int r = _mkdir(parent, name, mode, uid, gid, &in); if (r == 0) { @@ -10083,6 +10142,12 @@ int Client::ll_symlink(Inode *parent, const char *name, const char *value, tout(cct) << name << std::endl; tout(cct) << value << std::endl; + if (!cct->_conf->fuse_default_permissions) { + int r = may_create(parent, uid, gid); + if (r < 0) + return r; + } + InodeRef in; int r = _symlink(parent, name, value, uid, gid, &in); if (r == 0) { @@ -10151,6 +10216,11 @@ int Client::ll_unlink(Inode *in, const char *name, int uid, int gid) tout(cct) << vino.ino.val << std::endl; tout(cct) << name << std::endl; + if (!cct->_conf->fuse_default_permissions) { + int r = may_delete(in, name, uid, gid); + if (r < 0) + return r; + } return _unlink(in, name, uid, gid); } @@ -10212,6 +10282,12 @@ int Client::ll_rmdir(Inode *in, const char *name, int uid, int gid) tout(cct) << vino.ino.val << std::endl; tout(cct) << name << std::endl; + if (!cct->_conf->fuse_default_permissions) { + int r = may_delete(in, name, uid, gid); + if (r < 0) + return r; + } + return _rmdir(in, name, uid, gid); } @@ -10321,6 +10397,15 @@ int Client::ll_rename(Inode *parent, const char *name, Inode *newparent, tout(cct) << vnewparent.ino.val << std::endl; tout(cct) << newname << std::endl; + if (!cct->_conf->fuse_default_permissions) { + int r = may_delete(parent, name, uid, gid); + if (r < 0) + return r; + r = may_delete(newparent, newname, uid, gid); + if (r < 0 && r != -ENOENT) + return r; + } + return _rename(parent, name, newparent, newname, uid, gid); } @@ -10368,28 +10453,41 @@ int Client::_link(Inode *in, Inode *dir, const char *newname, int uid, int gid, return res; } -int Client::ll_link(Inode *parent, Inode *newparent, const char *newname, +int Client::ll_link(Inode *in, Inode *newparent, const char *newname, struct stat *attr, int uid, int gid) { Mutex::Locker lock(client_lock); - vinodeno_t vparent = _get_vino(parent); + vinodeno_t vino = _get_vino(in); vinodeno_t vnewparent = _get_vino(newparent); - ldout(cct, 3) << "ll_link " << parent << " to " << vnewparent << " " << + ldout(cct, 3) << "ll_link " << in << " to " << vnewparent << " " << newname << dendl; tout(cct) << "ll_link" << std::endl; - tout(cct) << vparent.ino.val << std::endl; + tout(cct) << vino.ino.val << std::endl; tout(cct) << vnewparent << std::endl; tout(cct) << newname << std::endl; + int r = 0; InodeRef target; - int r = _link(parent, newparent, newname, uid, gid, &target); + + if (!cct->_conf->fuse_default_permissions) { + if (S_ISDIR(in->mode)) { + r = -EPERM; + goto out; + } + r = may_create(newparent, uid, gid); + if (r < 0) + goto out; + } + + r = _link(in, newparent, newname, uid, gid, &target); if (r == 0) { assert(target); fill_stat(target, attr); _ll_get(target.get()); } +out: return r; } @@ -10598,8 +10696,13 @@ int Client::ll_create(Inode *parent, const char *name, mode_t mode, if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL)) return -EEXIST; - if (r == -ENOENT && (flags & O_CREAT)) { - r = _create(parent, name, flags, mode, &in, fhp /* may be NULL */, + if (r == -ENOENT && (flags & O_CREAT)) { + if (!cct->_conf->fuse_default_permissions) { + r = may_create(parent, uid, gid); + if (r < 0) + goto out; + } + r = _create(parent, name, flags, mode, &in, fhp /* may be NULL */, 0, 0, 0, NULL, &created, uid, gid); if (r < 0) goto out; diff --git a/src/client/Client.h b/src/client/Client.h index 0752e864d01b8..5bcf760b7733e 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -784,6 +784,8 @@ private: int inode_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want); int may_open(Inode *in, int flags, int uid=-1, int gid=-1); + int may_create(Inode *dir, int uid=-1, int gid=-1); + int may_delete(Inode *dir, const char *name, int uid=-1, int gid=-1); int _getgrouplist(gid_t **sgids, int uid=-1, int gid=-1); int check_data_pool_exist(string name, string value, const OSDMap *osdmap); -- 2.39.5