diff --git a/src/ceph_fuse.cc b/src/ceph_fuse.cc index eeb0c29f20863..5d54238acc617 100644 --- a/src/ceph_fuse.cc +++ b/src/ceph_fuse.cc @@ -189,6 +189,7 @@ int main(int argc, const char **argv, const char *envp[]) { Messenger *messenger = NULL; Client *client; CephFuse *cfuse; + UserPerm perms; MonClient *mc = new MonClient(g_ceph_context); int r = mc->build_initial_monmap(); @@ -234,10 +235,11 @@ int main(int argc, const char **argv, const char *envp[]) { } client->update_metadata("mount_point", cfuse->get_mount_point()); - + perms = client->pick_my_perms(); // start up fuse // use my argc, argv (make sure you pass a mount point!) - r = client->mount(g_conf->client_mountpoint.c_str(), g_ceph_context->_conf->fuse_require_active_mds); + r = client->mount(g_conf->client_mountpoint.c_str(), perms, + g_ceph_context->_conf->fuse_require_active_mds); if (r < 0) { if (r == CEPH_FUSE_NO_MDS_UP) cerr << "ceph-fuse[" << getpid() << "]: probably no MDS server is up?" << std::endl; diff --git a/src/client/Client.cc b/src/client/Client.cc index 0339c2807dbf4..a764e87f240dc 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -164,9 +164,10 @@ bool Client::CommandHook::call(std::string command, cmdmap_t& cmdmap, // ------------- -dir_result_t::dir_result_t(Inode *in) - : inode(in), owner_uid(-1), owner_gid(-1), offset(0), next_offset(2), - release_count(0), ordered_count(0), cache_index(0), start_shared_gen(0) +dir_result_t::dir_result_t(Inode *in, const UserPerm& perms) + : inode(in), offset(0), next_offset(2), + release_count(0), ordered_count(0), cache_index(0), start_shared_gen(0), + perms(perms) { } void Client::_reset_faked_inos() @@ -818,7 +819,8 @@ void Client::_fragmap_remove_non_leaves(Inode *in) } Inode * Client::add_update_inode(InodeStat *st, utime_t from, - MetaSession *session) + MetaSession *session, + const UserPerm& request_perms) { Inode *in; bool was_new = false; @@ -916,7 +918,9 @@ Inode * Client::add_update_inode(InodeStat *st, utime_t from, } if (in->snapid == CEPH_NOSNAP) { - add_update_cap(in, session, st->cap.cap_id, st->cap.caps, st->cap.seq, st->cap.mseq, inodeno_t(st->cap.realm), st->cap.flags); + add_update_cap(in, session, st->cap.cap_id, st->cap.caps, st->cap.seq, + st->cap.mseq, inodeno_t(st->cap.realm), st->cap.flags, + request_perms); if (in->auth_cap && in->auth_cap->session == session) in->max_size = st->max_size; } else @@ -1150,7 +1154,8 @@ void Client::insert_readdir_results(MetaRequest *request, MetaSession *session, ldout(cct, 15) << "" << i << ": '" << dname << "'" << dendl; - Inode *in = add_update_inode(&ist, request->sent_stamp, session); + Inode *in = add_update_inode(&ist, request->sent_stamp, session, + request->perms); Dentry *dn; if (diri->dir->dentries.count(dname)) { Dentry *olddn = diri->dir->dentries[dname]; @@ -1305,12 +1310,14 @@ Inode* Client::insert_trace(MetaRequest *request, MetaSession *session) assert(0 == "MDS reply does not contain xattrs"); } - in = add_update_inode(&ist, request->sent_stamp, session); + in = add_update_inode(&ist, request->sent_stamp, session, + request->perms); } Inode *diri = NULL; if (reply->head.is_dentry) { - diri = add_update_inode(&dirst, request->sent_stamp, session); + diri = add_update_inode(&dirst, request->sent_stamp, session, + request->perms); update_dir_dist(diri, &dst); // dir stat info is attached to .. if (in) { @@ -1516,7 +1523,7 @@ void Client::dump_mds_requests(Formatter *f) int Client::verify_reply_trace(int r, MetaRequest *request, MClientReply *reply, InodeRef *ptarget, bool *pcreated, - int uid, int gid) + const UserPerm& perms) { // check whether this request actually did the create, and set created flag bufferlist extra_bl; @@ -1557,7 +1564,8 @@ int Client::verify_reply_trace(int r, << " got_ino " << got_created_ino << " ino " << created_ino << dendl; - r = _do_lookup(d->dir->parent_inode, d->name, request->regetattr_mask, &target, uid, gid); + r = _do_lookup(d->dir->parent_inode, d->name, request->regetattr_mask, + &target, perms); } else { // if the dentry is not linked, just do our best. see #5021. assert(0 == "how did this happen? i want logs!"); @@ -1566,7 +1574,7 @@ int Client::verify_reply_trace(int r, Inode *in = request->inode(); ldout(cct, 10) << "make_request got traceless reply, forcing getattr on #" << in->ino << dendl; - r = _getattr(in, request->regetattr_mask, uid, gid, true); + r = _getattr(in, request->regetattr_mask, perms, true); target = in; } if (r >= 0) { @@ -1599,15 +1607,14 @@ int Client::verify_reply_trace(int r, * a request). * * @param request the MetaRequest to execute - * @param uid uid to execute as - * @param gid gid to execute as + * @param perms The user uid/gid to execute as (eventually, full group lists?) * @param ptarget [optional] address to store a pointer to the target inode we want to create or operate on * @param pcreated [optional; required if ptarget] where to store a bool of whether our create atomically created a file * @param use_mds [optional] prefer a specific mds (-1 for default) * @param pdirbl [optional; disallowed if ptarget] where to pass extra reply payload to the caller */ -int Client::make_request(MetaRequest *request, - int uid, int gid, +int Client::make_request(MetaRequest *request, + const UserPerm& perms, InodeRef *ptarget, bool *pcreated, int use_mds, bufferlist *pdirbl) @@ -1626,13 +1633,7 @@ int Client::make_request(MetaRequest *request, if (oldest_tid == 0 && request->get_op() != CEPH_MDS_OP_SETFILELOCK) oldest_tid = tid; - if (uid < 0) - uid = get_uid(); - if (gid < 0) - gid = get_gid(); - - request->set_caller_uid(uid); - request->set_caller_gid(gid); + request->set_caller_perms(perms); if (cct->_conf->client_inject_fixed_oldest_tid) { ldout(cct, 20) << __func__ << " injecting fixed oldest_client_tid(1)" << dendl; @@ -1736,7 +1737,7 @@ int Client::make_request(MetaRequest *request, request->dispatch_cond = 0; if (r >= 0 && ptarget) - r = verify_reply_trace(r, request, reply, ptarget, pcreated, uid, gid); + r = verify_reply_trace(r, request, reply, ptarget, pcreated, perms); if (pdirbl) pdirbl->claim(reply->get_extra_bl()); @@ -2177,6 +2178,9 @@ MClientRequest* Client::build_client_request(MetaRequest *request) req->set_data(request->data); req->set_retry_attempt(request->retry_attempt++); req->head.num_fwd = request->num_fwd; + const gid_t *_gids; + int gid_count = request->perms.get_gids(&_gids); + req->set_gid_list(gid_count, _gids); return req; } @@ -3756,7 +3760,7 @@ void Client::check_cap_issue(Inode *in, Cap *cap, unsigned issued) void Client::add_update_cap(Inode *in, MetaSession *mds_session, uint64_t cap_id, unsigned issued, unsigned seq, unsigned mseq, inodeno_t realm, - int flags) + int flags, const UserPerm& cap_perms) { Cap *cap = 0; mds_rank_t mds = mds_session->mds_num; @@ -3789,6 +3793,7 @@ void Client::add_update_cap(Inode *in, MetaSession *mds_session, uint64_t cap_id ldout(cct, 15) << "add_update_cap first one, opened snaprealm " << in->snaprealm << dendl; } in->caps[mds] = cap = new Cap; + mds_session->caps.push_back(&cap->cap_item); cap->session = mds_session; cap->inode = in; @@ -3817,6 +3822,7 @@ void Client::add_update_cap(Inode *in, MetaSession *mds_session, uint64_t cap_id cap->seq = seq; cap->issue_seq = seq; cap->mseq = mseq; + cap->latest_perms = cap_perms; ldout(cct, 10) << "add_update_cap issued " << ccap_string(old_caps) << " -> " << ccap_string(cap->issued) << " from mds." << mds << " on " << *in @@ -4591,17 +4597,23 @@ void Client::handle_cap_import(MetaSession *session, Inode *in, MClientCaps *m) ldout(cct, 5) << "handle_cap_import ino " << m->get_ino() << " mseq " << m->get_mseq() << " IMPORT from mds." << mds << dendl; + const mds_rank_t peer_mds = mds_rank_t(m->peer.mds); + Cap *cap = NULL; + UserPerm cap_perms; + if (m->peer.cap_id && in->caps.count(peer_mds)) { + cap = in->caps[peer_mds]; + if (cap) { + cap_perms = cap->latest_perms; + } + } + // add/update it update_snap_trace(m->snapbl); add_update_cap(in, session, m->get_cap_id(), m->get_caps(), m->get_seq(), m->get_mseq(), m->get_realm(), - CEPH_CAP_FLAG_AUTH); - - const mds_rank_t peer_mds = mds_rank_t(m->peer.mds); - - if (m->peer.cap_id && in->caps.count(peer_mds)) { - Cap *cap = in->caps[peer_mds]; - if (cap && cap->cap_id == m->peer.cap_id) + CEPH_CAP_FLAG_AUTH, cap_perms); + + if (cap && cap->cap_id == m->peer.cap_id) { remove_cap(cap, (m->peer.flags & CEPH_CAP_FLAG_RELEASE)); } @@ -4648,7 +4660,8 @@ void Client::handle_cap_export(MetaSession *session, Inode *in, MClientCaps *m) } else { add_update_cap(in, tsession, m->peer.cap_id, cap->issued, m->peer.seq - 1, m->peer.mseq, (uint64_t)-1, - cap == in->auth_cap ? CEPH_CAP_FLAG_AUTH : 0); + cap == in->auth_cap ? CEPH_CAP_FLAG_AUTH : 0, + cap->latest_perms); } } else { if (cap == in->auth_cap) @@ -4970,7 +4983,7 @@ void Client::handle_cap_grant(MetaSession *session, Inode *in, Cap *cap, MClient m->put(); } -int Client::_getgrouplist(gid_t** sgids, int uid, int gid) +int Client::_getgrouplist(gid_t** sgids, uid_t uid, gid_t gid) { // cppcheck-suppress variableScope int sgid_count; @@ -5027,87 +5040,84 @@ int Client::_getgrouplist(gid_t** sgids, int uid, int gid) #endif } -int Client::inode_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want) +int Client::inode_permission(Inode *in, const UserPerm& perms, unsigned want) { - if (uid == 0) + if (perms.uid() == 0) return 0; - - if (uid != in->uid && (in->mode & S_IRWXG)) { - int ret = _posix_acl_permission(in, uid, groups, want); + + if (perms.uid() != in->uid && (in->mode & S_IRWXG)) { + int ret = _posix_acl_permission(in, perms, want); if (ret != -EAGAIN) return ret; } // check permissions before doing anything else - if (!in->check_mode(uid, groups, want)) + if (!in->check_mode(perms, want)) return -EACCES; return 0; } -int Client::xattr_permission(Inode *in, const char *name, unsigned want, int uid, int gid) +int Client::xattr_permission(Inode *in, const char *name, unsigned want, + const UserPerm& perms) { - if (uid < 0) - uid = get_uid(); - if (gid < 0) - gid = get_gid(); - RequestUserGroups groups(this, uid, gid); - - int r = _getattr_for_perm(in, uid, gid); + int r = _getattr_for_perm(in, perms); if (r < 0) goto out; r = 0; if (strncmp(name, "system.", 7) == 0) { - if ((want & MAY_WRITE) && (uid != 0 && (uid_t)uid != in->uid)) + if ((want & MAY_WRITE) && (perms.uid() != 0 && perms.uid() != in->uid)) r = -EPERM; } else { - r = inode_permission(in, uid, groups, want); + r = inode_permission(in, perms, want); } out: ldout(cct, 3) << __func__ << " " << in << " = " << r << dendl; return r; } -int Client::may_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid) -{ - if (uid < 0) - uid = get_uid(); - if (gid < 0) - gid = get_gid(); - RequestUserGroups groups(this, uid, gid); +ostream& operator<<(ostream &out, const UserPerm& perm) { + out << "UserPerm(uid: " << perm.uid() << ", gid: " << perm.gid() << ")"; + return out; +} - int r = _getattr_for_perm(in, uid, gid); +int Client::may_setattr(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms) +{ + ldout(cct, 20) << __func__ << *in << "; " << perms << dendl; + int r = _getattr_for_perm(in, perms); if (r < 0) goto out; if (mask & CEPH_SETATTR_SIZE) { - r = inode_permission(in, uid, groups, MAY_WRITE); + r = inode_permission(in, perms, MAY_WRITE); if (r < 0) goto out; } r = -EPERM; if (mask & CEPH_SETATTR_UID) { - if (uid != 0 && ((uid_t)uid != in->uid || stx->stx_uid != in->uid)) + if (perms.uid() != 0 && (perms.uid() != in->uid || stx->stx_uid != in->uid)) goto out; } if (mask & CEPH_SETATTR_GID) { - if (uid != 0 && ((uid_t)uid != in->uid || - (!groups.is_in(stx->stx_gid) && stx->stx_gid != in->gid))) + if (perms.uid() != 0 && (perms.uid() != in->uid || + (!perms.gid_in_groups(stx->stx_gid) && stx->stx_gid != in->gid))) goto out; } if (mask & CEPH_SETATTR_MODE) { - if (uid != 0 && (uid_t)uid != in->uid) + if (perms.uid() != 0 && perms.uid() != in->uid) goto out; gid_t i_gid = (mask & CEPH_SETATTR_GID) ? stx->stx_gid : in->gid; - if (uid != 0 && !groups.is_in(i_gid)) + if (perms.uid() != 0 && !perms.gid_in_groups(i_gid)) stx->stx_mode &= ~S_ISGID; } - if (mask & (CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME | CEPH_SETATTR_MTIME | CEPH_SETATTR_ATIME)) { - if (uid != 0 && (uid_t)uid != in->uid) { + if (mask & (CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME | + CEPH_SETATTR_MTIME | CEPH_SETATTR_ATIME)) { + if (perms.uid() != 0 && perms.uid() != in->uid) { int check_mask = CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME; if (!(mask & CEPH_SETATTR_MTIME_NOW)) check_mask |= CEPH_SETATTR_MTIME; @@ -5116,7 +5126,7 @@ int Client::may_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in if (check_mask & mask) { goto out; } else { - r = inode_permission(in, uid, groups, MAY_WRITE); + r = inode_permission(in, perms, MAY_WRITE); if (r < 0) goto out; } @@ -5128,8 +5138,9 @@ int Client::may_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in return r; } -int Client::may_open(Inode *in, int flags, int uid, int gid) +int Client::may_open(Inode *in, int flags, const UserPerm& perms) { + ldout(cct, 20) << __func__ << *in << "; " << perms << dendl; unsigned want = 0; if ((flags & O_ACCMODE) == O_WRONLY) @@ -5141,12 +5152,6 @@ int Client::may_open(Inode *in, int flags, int uid, int gid) if (flags & O_TRUNC) want |= MAY_WRITE; - if (uid < 0) - uid = get_uid(); - if (gid < 0) - gid = get_gid(); - RequestUserGroups groups(this, uid, gid); - int r = 0; switch (in->mode & S_IFMT) { case S_IFLNK: @@ -5160,75 +5165,60 @@ int Client::may_open(Inode *in, int flags, int uid, int gid) break; } - r = _getattr_for_perm(in, uid, gid); + r = _getattr_for_perm(in, perms); if (r < 0) goto out; - r = inode_permission(in, uid, groups, want); + r = inode_permission(in, perms, want); out: ldout(cct, 3) << __func__ << " " << in << " = " << r << dendl; return r; } -int Client::may_lookup(Inode *dir, int uid, int gid) +int Client::may_lookup(Inode *dir, const UserPerm& perms) { - if (uid < 0) - uid = get_uid(); - if (gid < 0) - gid = get_gid(); - RequestUserGroups groups(this, uid, gid); - - int r = _getattr_for_perm(dir, uid, gid); + ldout(cct, 20) << __func__ << *dir << "; " << perms << dendl; + int r = _getattr_for_perm(dir, perms); if (r < 0) goto out; - r = inode_permission(dir, uid, groups, MAY_EXEC); + r = inode_permission(dir, perms, MAY_EXEC); out: ldout(cct, 3) << __func__ << " " << dir << " = " << r << dendl; return r; } -int Client::may_create(Inode *dir, int uid, int gid) +int Client::may_create(Inode *dir, const UserPerm& perms) { - if (uid < 0) - uid = get_uid(); - if (gid < 0) - gid = get_gid(); - RequestUserGroups groups(this, uid, gid); - - int r = _getattr_for_perm(dir, uid, gid); + ldout(cct, 20) << __func__ << *dir << "; " << perms << dendl; + int r = _getattr_for_perm(dir, perms); if (r < 0) goto out; - r = inode_permission(dir, uid, groups, MAY_EXEC | MAY_WRITE); + r = inode_permission(dir, perms, 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) +int Client::may_delete(Inode *dir, const char *name, const UserPerm& perms) { - if (uid < 0) - uid = get_uid(); - if (gid < 0) - gid = get_gid(); - RequestUserGroups groups(this, uid, gid); - - int r = _getattr_for_perm(dir, uid, gid); + ldout(cct, 20) << __func__ << *dir << "; " << "; name " << name << "; " << perms << dendl; + int r = _getattr_for_perm(dir, perms); if (r < 0) goto out; - r = inode_permission(dir, uid, groups, MAY_EXEC | MAY_WRITE); + r = inode_permission(dir, perms, MAY_EXEC | MAY_WRITE); if (r < 0) goto out; /* 'name == NULL' means rmsnap */ - if (uid != 0 && name && (dir->mode & S_ISVTX)) { + if (perms.uid() != 0 && name && (dir->mode & S_ISVTX)) { InodeRef otherin; - r = _lookup(dir, name, CEPH_CAP_AUTH_SHARED, &otherin, uid, gid); + r = _lookup(dir, name, CEPH_CAP_AUTH_SHARED, &otherin, perms); if (r < 0) goto out; - if (dir->uid != (uid_t)uid && otherin->uid != (uid_t)uid) + if (dir->uid != perms.uid() && otherin->uid != perms.uid()) r = -EPERM; } out: @@ -5236,19 +5226,14 @@ int Client::may_delete(Inode *dir, const char *name, int uid, int gid) return r; } -int Client::may_hardlink(Inode *in, int uid, int gid) +int Client::may_hardlink(Inode *in, const UserPerm& perms) { - if (uid < 0) - uid = get_uid(); - if (gid < 0) - gid = get_gid(); - RequestUserGroups groups(this, uid, gid); - - int r = _getattr_for_perm(in, uid, gid); + ldout(cct, 20) << __func__ << *in << "; " << perms << dendl; + int r = _getattr_for_perm(in, perms); if (r < 0) goto out; - if (uid == 0 || (uid_t)uid == in->uid) { + if (perms.uid() == 0 || perms.uid() == in->uid) { r = 0; goto out; } @@ -5263,13 +5248,13 @@ int Client::may_hardlink(Inode *in, int uid, int gid) if ((in->mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) goto out; - r = inode_permission(in, uid, groups, MAY_READ | MAY_WRITE); + r = inode_permission(in, perms, MAY_READ | MAY_WRITE); out: ldout(cct, 3) << __func__ << " " << in << " = " << r << dendl; return r; } -int Client::_getattr_for_perm(Inode *in, int uid, int gid) +int Client::_getattr_for_perm(Inode *in, const UserPerm& perms) { int mask = CEPH_STAT_CAP_MODE; bool force = false; @@ -5277,7 +5262,7 @@ int Client::_getattr_for_perm(Inode *in, int uid, int gid) mask |= CEPH_STAT_CAP_XATTR; force = in->xattr_version == 0; } - return _getattr(in, mask, uid, gid, force); + return _getattr(in, mask, perms, force); } vinodeno_t Client::_get_vino(Inode *in) @@ -5550,7 +5535,8 @@ void Client::handle_command_reply(MCommandReply *m) // ------------------- // MOUNT -int Client::mount(const std::string &mount_root, bool require_mds) +int Client::mount(const std::string &mount_root, const UserPerm& perms, + bool require_mds) { Mutex::Locker lock(client_lock); @@ -5613,7 +5599,7 @@ int Client::mount(const std::string &mount_root, bool require_mds) MetaRequest *req = new MetaRequest(CEPH_MDS_OP_GETATTR); req->set_filepath(fp); req->head.args.getattr.mask = CEPH_STAT_CAP_INODE_ALL; - int res = make_request(req, -1, -1); + int res = make_request(req, perms); if (res < 0) { if (res == -EACCES && root) { ldout(cct, 1) << __func__ << " EACCES on parent of mount point; quotas may not work" << dendl; @@ -5893,8 +5879,8 @@ void Client::renew_caps(MetaSession *session) // =============================================================== // high level (POSIXy) interface -int Client::_do_lookup(Inode *dir, const string& name, int mask, InodeRef *target, - int uid, int gid) +int Client::_do_lookup(Inode *dir, const string& name, int mask, + InodeRef *target, const UserPerm& perms) { int op = dir->snapid == CEPH_SNAPDIR ? CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP; MetaRequest *req = new MetaRequest(op); @@ -5909,13 +5895,13 @@ int Client::_do_lookup(Inode *dir, const string& name, int mask, InodeRef *targe ldout(cct, 10) << "_do_lookup on " << path << dendl; - int r = make_request(req, uid, gid, target); + int r = make_request(req, perms, target); ldout(cct, 10) << "_do_lookup res is " << r << dendl; return r; } -int Client::_lookup(Inode *dir, const string& dname, int mask, - InodeRef *target, int uid, int gid) +int Client::_lookup(Inode *dir, const string& dname, int mask, InodeRef *target, + const UserPerm& perms) { int r = 0; Dentry *dn = NULL; @@ -5997,7 +5983,7 @@ int Client::_lookup(Inode *dir, const string& dname, int mask, } } - r = _do_lookup(dir, dname, mask, target, uid, gid); + r = _do_lookup(dir, dname, mask, target, perms); goto done; hit_dn: @@ -6048,7 +6034,8 @@ int Client::get_or_create(Inode *dir, const char* name, return 0; } -int Client::path_walk(const filepath& origpath, InodeRef *end, bool followsym, +int Client::path_walk(const filepath& origpath, InodeRef *end, + const UserPerm& perms, bool followsym, int mask, int uid, int gid) { filepath path = origpath; @@ -6059,11 +6046,6 @@ int Client::path_walk(const filepath& origpath, InodeRef *end, bool followsym, cur = cwd; assert(cur); - if (uid < 0) - uid = get_uid(); - if (gid < 0) - gid = get_gid(); - ldout(cct, 10) << "path_walk " << path << dendl; int symlinks = 0; @@ -6076,7 +6058,7 @@ int Client::path_walk(const filepath& origpath, InodeRef *end, bool followsym, ldout(cct, 20) << " (path is " << path << ")" << dendl; InodeRef next; if (cct->_conf->client_permissions) { - int r = may_lookup(cur.get(), uid, gid); + int r = may_lookup(cur.get(), perms); if (r < 0) return r; caps = CEPH_CAP_AUTH_SHARED; @@ -6085,8 +6067,7 @@ int Client::path_walk(const filepath& origpath, InodeRef *end, bool followsym, /* Get extra requested caps on the last component */ if (i == (path.depth() - 1)) caps |= mask; - - int r = _lookup(cur.get(), dname, caps, &next, uid, gid); + int r = _lookup(cur.get(), dname, caps, &next, perms); if (r < 0) return r; // only follow trailing symlink if followsym. always follow @@ -6139,7 +6120,7 @@ int Client::path_walk(const filepath& origpath, InodeRef *end, bool followsym, // namespace ops -int Client::link(const char *relexisting, const char *relpath) +int Client::link(const char *relexisting, const char *relpath, const UserPerm& perm) { Mutex::Locker lock(client_lock); tout(cct) << "link" << std::endl; @@ -6152,10 +6133,10 @@ int Client::link(const char *relexisting, const char *relpath) path.pop_dentry(); InodeRef in, dir; - int r = path_walk(existing, &in); + int r = path_walk(existing, &in, perm, true); if (r < 0) goto out; - r = path_walk(path, &dir); + r = path_walk(path, &dir, perm, true); if (r < 0) goto out; if (cct->_conf->client_permissions) { @@ -6163,19 +6144,19 @@ int Client::link(const char *relexisting, const char *relpath) r = -EPERM; goto out; } - r = may_hardlink(in.get()); + r = may_hardlink(in.get(), perm); if (r < 0) goto out; - r = may_create(dir.get()); + r = may_create(dir.get(), perm); if (r < 0) goto out; } - r = _link(in.get(), dir.get(), name.c_str()); + r = _link(in.get(), dir.get(), name.c_str(), perm); out: return r; } -int Client::unlink(const char *relpath) +int Client::unlink(const char *relpath, const UserPerm& perm) { Mutex::Locker lock(client_lock); tout(cct) << "unlink" << std::endl; @@ -6185,18 +6166,18 @@ int Client::unlink(const char *relpath) string name = path.last_dentry(); path.pop_dentry(); InodeRef dir; - int r = path_walk(path, &dir); + int r = path_walk(path, &dir, perm); if (r < 0) return r; if (cct->_conf->client_permissions) { - r = may_delete(dir.get(), name.c_str()); + r = may_delete(dir.get(), name.c_str(), perm); if (r < 0) return r; } - return _unlink(dir.get(), name.c_str()); + return _unlink(dir.get(), name.c_str(), perm); } -int Client::rename(const char *relfrom, const char *relto) +int Client::rename(const char *relfrom, const char *relto, const UserPerm& perm) { Mutex::Locker lock(client_lock); tout(cct) << "rename" << std::endl; @@ -6211,29 +6192,29 @@ int Client::rename(const char *relfrom, const char *relto) to.pop_dentry(); InodeRef fromdir, todir; - int r = path_walk(from, &fromdir); + int r = path_walk(from, &fromdir, perm); if (r < 0) goto out; - r = path_walk(to, &todir); + r = path_walk(to, &todir, perm); if (r < 0) goto out; if (cct->_conf->client_permissions) { - int r = may_delete(fromdir.get(), fromname.c_str()); + int r = may_delete(fromdir.get(), fromname.c_str(), perm); if (r < 0) return r; - r = may_delete(todir.get(), toname.c_str()); + r = may_delete(todir.get(), toname.c_str(), perm); if (r < 0 && r != -ENOENT) return r; } - r = _rename(fromdir.get(), fromname.c_str(), todir.get(), toname.c_str()); + r = _rename(fromdir.get(), fromname.c_str(), todir.get(), toname.c_str(), perm); out: return r; } // dirs -int Client::mkdir(const char *relpath, mode_t mode) +int Client::mkdir(const char *relpath, mode_t mode, const UserPerm& perm) { Mutex::Locker lock(client_lock); tout(cct) << "mkdir" << std::endl; @@ -6245,18 +6226,18 @@ int Client::mkdir(const char *relpath, mode_t mode) string name = path.last_dentry(); path.pop_dentry(); InodeRef dir; - int r = path_walk(path, &dir); + int r = path_walk(path, &dir, perm); if (r < 0) return r; if (cct->_conf->client_permissions) { - r = may_create(dir.get()); + r = may_create(dir.get(), perm); if (r < 0) return r; } - return _mkdir(dir.get(), name.c_str(), mode); + return _mkdir(dir.get(), name.c_str(), mode, perm); } -int Client::mkdirs(const char *relpath, mode_t mode) +int Client::mkdirs(const char *relpath, mode_t mode, const UserPerm& perms) { Mutex::Locker lock(client_lock); ldout(cct, 10) << "Client::mkdirs " << relpath << dendl; @@ -6264,9 +6245,6 @@ int Client::mkdirs(const char *relpath, mode_t mode) tout(cct) << relpath << std::endl; tout(cct) << mode << std::endl; - uid_t uid = get_uid(); - gid_t gid = get_gid(); - //get through existing parts of path filepath path(relpath); unsigned int i; @@ -6275,12 +6253,12 @@ int Client::mkdirs(const char *relpath, mode_t mode) cur = cwd; for (i=0; i_conf->client_permissions) { - r = may_lookup(cur.get(), uid, gid); + r = may_lookup(cur.get(), perms); if (r < 0) break; caps = CEPH_CAP_AUTH_SHARED; } - r = _lookup(cur.get(), path[i].c_str(), caps, &next, uid, gid); + r = _lookup(cur.get(), path[i].c_str(), caps, &next, perms); if (r < 0) break; cur.swap(next); @@ -6292,12 +6270,12 @@ int Client::mkdirs(const char *relpath, mode_t mode) //make new directory at each level for (; i_conf->client_permissions) { - r = may_create(cur.get(), uid, gid); + r = may_create(cur.get(), perms); if (r < 0) return r; } //make new dir - r = _mkdir(cur.get(), path[i].c_str(), mode, uid, gid, &next); + r = _mkdir(cur.get(), path[i].c_str(), mode, perms, &next); //check proper creation/existence if (r < 0) return r; //move to new dir and continue @@ -6308,7 +6286,7 @@ int Client::mkdirs(const char *relpath, mode_t mode) return 0; } -int Client::rmdir(const char *relpath) +int Client::rmdir(const char *relpath, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "rmdir" << std::endl; @@ -6317,18 +6295,18 @@ int Client::rmdir(const char *relpath) string name = path.last_dentry(); path.pop_dentry(); InodeRef dir; - int r = path_walk(path, &dir); + int r = path_walk(path, &dir, perms); if (r < 0) return r; if (cct->_conf->client_permissions) { - int r = may_delete(dir.get(), name.c_str()); + int r = may_delete(dir.get(), name.c_str(), perms); if (r < 0) return r; } - return _rmdir(dir.get(), name.c_str()); + return _rmdir(dir.get(), name.c_str(), perms); } -int Client::mknod(const char *relpath, mode_t mode, dev_t rdev) +int Client::mknod(const char *relpath, mode_t mode, const UserPerm& perms, dev_t rdev) { Mutex::Locker lock(client_lock); tout(cct) << "mknod" << std::endl; @@ -6339,20 +6317,20 @@ int Client::mknod(const char *relpath, mode_t mode, dev_t rdev) string name = path.last_dentry(); path.pop_dentry(); InodeRef dir; - int r = path_walk(path, &dir); + int r = path_walk(path, &dir, perms); if (r < 0) return r; if (cct->_conf->client_permissions) { - int r = may_create(dir.get()); + int r = may_create(dir.get(), perms); if (r < 0) return r; } - return _mknod(dir.get(), name.c_str(), mode, rdev); + return _mknod(dir.get(), name.c_str(), mode, rdev, perms); } // symlinks -int Client::symlink(const char *target, const char *relpath) +int Client::symlink(const char *target, const char *relpath, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "symlink" << std::endl; @@ -6363,18 +6341,18 @@ int Client::symlink(const char *target, const char *relpath) string name = path.last_dentry(); path.pop_dentry(); InodeRef dir; - int r = path_walk(path, &dir); + int r = path_walk(path, &dir, perms); if (r < 0) return r; if (cct->_conf->client_permissions) { - int r = may_create(dir.get()); + int r = may_create(dir.get(), perms); if (r < 0) return r; } - return _symlink(dir.get(), name.c_str(), target); + return _symlink(dir.get(), name.c_str(), target, perms); } -int Client::readlink(const char *relpath, char *buf, loff_t size) +int Client::readlink(const char *relpath, char *buf, loff_t size, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "readlink" << std::endl; @@ -6382,7 +6360,7 @@ int Client::readlink(const char *relpath, char *buf, loff_t size) filepath path(relpath); InodeRef in; - int r = path_walk(path, &in, false); + int r = path_walk(path, &in, perms, false); if (r < 0) return r; @@ -6405,7 +6383,7 @@ int Client::_readlink(Inode *in, char *buf, size_t size) // inode stuff -int Client::_getattr(Inode *in, int mask, int uid, int gid, bool force) +int Client::_getattr(Inode *in, int mask, const UserPerm& perms, bool force) { bool yes = in->caps_issued_mask(mask); @@ -6420,13 +6398,13 @@ int Client::_getattr(Inode *in, int mask, int uid, int gid, bool force) req->set_inode(in); req->head.args.getattr.mask = mask; - int res = make_request(req, uid, gid); + int res = make_request(req, perms); ldout(cct, 10) << "_getattr result=" << res << dendl; return res; } -int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid, - InodeRef *inp) +int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms, InodeRef *inp) { int issued = in->caps_issued(); @@ -6438,19 +6416,15 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in } if ((mask & CEPH_SETATTR_SIZE) && (unsigned long)stx->stx_size > in->size && - is_quota_bytes_exceeded(in, (unsigned long)stx->stx_size - in->size)) { + is_quota_bytes_exceeded(in, (unsigned long)stx->stx_size - in->size, + perms)) { return -EDQUOT; } - if (uid < 0) { - uid = get_uid(); - gid = get_gid(); - } - // make the change locally? - if ((in->cap_dirtier_uid >= 0 && uid != in->cap_dirtier_uid) || - (in->cap_dirtier_gid >= 0 && gid != in->cap_dirtier_gid)) { - ldout(cct, 10) << __func__ << " caller " << uid << ":" << gid + if ((in->cap_dirtier_uid >= 0 && perms.uid() != in->cap_dirtier_uid) || + (in->cap_dirtier_gid >= 0 && perms.gid() != in->cap_dirtier_gid)) { + ldout(cct, 10) << __func__ << " caller " << perms.uid() << ":" << perms.gid() << " != cap dirtier " << in->cap_dirtier_uid << ":" << in->cap_dirtier_gid << ", forcing sync setattr" << dendl; @@ -6473,8 +6447,8 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in if (!mask) { // caller just needs us to bump the ctime in->ctime = ceph_clock_now(cct); - in->cap_dirtier_uid = uid; - in->cap_dirtier_gid = gid; + in->cap_dirtier_uid = perms.uid(); + in->cap_dirtier_gid = perms.gid(); if (issued & CEPH_CAP_AUTH_EXCL) mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); else if (issued & CEPH_CAP_FILE_EXCL) @@ -6488,8 +6462,8 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in if (in->caps_issued_mask(CEPH_CAP_AUTH_EXCL)) { if (mask & CEPH_SETATTR_MODE) { in->ctime = ceph_clock_now(cct); - in->cap_dirtier_uid = uid; - in->cap_dirtier_gid = gid; + in->cap_dirtier_uid = perms.uid(); + in->cap_dirtier_gid = perms.gid(); in->mode = (in->mode & ~07777) | (stx->stx_mode & 07777); mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_MODE; @@ -6497,8 +6471,8 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in } if (mask & CEPH_SETATTR_UID) { in->ctime = ceph_clock_now(cct); - in->cap_dirtier_uid = uid; - in->cap_dirtier_gid = gid; + in->cap_dirtier_uid = perms.uid(); + in->cap_dirtier_gid = perms.gid(); in->uid = stx->stx_uid; mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_UID; @@ -6506,8 +6480,8 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in } if (mask & CEPH_SETATTR_GID) { in->ctime = ceph_clock_now(cct); - in->cap_dirtier_uid = uid; - in->cap_dirtier_gid = gid; + in->cap_dirtier_uid = perms.uid(); + in->cap_dirtier_gid = perms.gid(); in->gid = stx->stx_gid; mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_GID; @@ -6515,8 +6489,8 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in } if (mask & CEPH_SETATTR_BTIME) { in->ctime = ceph_clock_now(cct); - in->cap_dirtier_uid = uid; - in->cap_dirtier_gid = gid; + in->cap_dirtier_uid = perms.uid(); + in->cap_dirtier_gid = perms.gid(); in->btime = utime_t(stx->stx_btime); mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_BTIME; @@ -6530,8 +6504,8 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in if (mask & CEPH_SETATTR_ATIME) in->atime = utime_t(stx->stx_atime); in->ctime = ceph_clock_now(cct); - in->cap_dirtier_uid = uid; - in->cap_dirtier_gid = gid; + in->cap_dirtier_uid = perms.uid(); + in->cap_dirtier_gid = perms.gid(); in->time_warp_seq++; mark_caps_dirty(in, CEPH_CAP_FILE_EXCL); mask &= ~(CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME); @@ -6595,7 +6569,7 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, in req->regetattr_mask = mask; - int res = make_request(req, uid, gid, inp); + int res = make_request(req, perms, inp); ldout(cct, 10) << "_setattr result=" << res << dendl; return res; } @@ -6611,41 +6585,44 @@ void Client::stat_to_statx(struct stat *st, struct ceph_statx *stx) stx->stx_atime = st->st_atim; } -int Client::__setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid, - InodeRef *inp) +int Client::__setattrx(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms, InodeRef *inp) { - int ret = _do_setattr(in, stx, mask, uid, gid, inp); + int ret = _do_setattr(in, stx, mask, perms, inp); if (ret < 0) return ret; if (mask & CEPH_SETATTR_MODE) - ret = _posix_acl_chmod(in, stx->stx_mode, uid, gid); + ret = _posix_acl_chmod(in, stx->stx_mode, perms); return ret; } -int Client::_setattrx(InodeRef &in, struct ceph_statx *stx, int mask) +int Client::_setattrx(InodeRef &in, struct ceph_statx *stx, int mask, + const UserPerm& perms) { mask &= (CEPH_SETATTR_MODE | CEPH_SETATTR_UID | CEPH_SETATTR_GID | CEPH_SETATTR_MTIME | CEPH_SETATTR_ATIME | CEPH_SETATTR_SIZE | CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME); if (cct->_conf->client_permissions) { - int r = may_setattr(in.get(), stx, mask); + int r = may_setattr(in.get(), stx, mask, perms); if (r < 0) return r; } - return __setattrx(in.get(), stx, mask); + return __setattrx(in.get(), stx, mask, perms); } -int Client::_setattr(InodeRef &in, struct stat *attr, int mask) +int Client::_setattr(InodeRef &in, struct stat *attr, int mask, + const UserPerm& perms) { struct ceph_statx stx; stat_to_statx(attr, &stx); mask &= ~CEPH_SETATTR_BTIME; - return _setattrx(in, &stx, mask); + return _setattrx(in, &stx, mask, perms); } -int Client::setattr(const char *relpath, struct stat *attr, int mask) +int Client::setattr(const char *relpath, struct stat *attr, int mask, + const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "setattr" << std::endl; @@ -6654,13 +6631,14 @@ int Client::setattr(const char *relpath, struct stat *attr, int mask) filepath path(relpath); InodeRef in; - int r = path_walk(path, &in); + int r = path_walk(path, &in, perms); if (r < 0) return r; - return _setattr(in, attr, mask); + return _setattr(in, attr, mask, perms); } -int Client::setattrx(const char *relpath, struct ceph_statx *stx, int mask, int flags) +int Client::setattrx(const char *relpath, struct ceph_statx *stx, int mask, + const UserPerm& perms, int flags) { Mutex::Locker lock(client_lock); tout(cct) << "setattrx" << std::endl; @@ -6669,13 +6647,13 @@ int Client::setattrx(const char *relpath, struct ceph_statx *stx, int mask, int filepath path(relpath); InodeRef in; - int r = path_walk(path, &in, flags & AT_SYMLINK_NOFOLLOW); + int r = path_walk(path, &in, perms, flags & AT_SYMLINK_NOFOLLOW); if (r < 0) return r; - return _setattrx(in, stx, mask); + return _setattrx(in, stx, mask, perms); } -int Client::fsetattr(int fd, struct stat *attr, int mask) +int Client::fsetattr(int fd, struct stat *attr, int mask, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "fsetattr" << std::endl; @@ -6689,11 +6667,11 @@ int Client::fsetattr(int fd, struct stat *attr, int mask) if (f->flags & O_PATH) return -EBADF; #endif - return _setattr(f->inode, attr, mask); + return _setattr(f->inode, attr, mask, perms); } -int Client::stat(const char *relpath, struct stat *stbuf, - frag_info_t *dirstat, int mask) +int Client::stat(const char *relpath, struct stat *stbuf, const UserPerm& perms, + frag_info_t *dirstat, int mask) { ldout(cct, 3) << "stat enter (relpath " << relpath << " mask " << mask << ")" << dendl; Mutex::Locker lock(client_lock); @@ -6701,10 +6679,10 @@ int Client::stat(const char *relpath, struct stat *stbuf, tout(cct) << relpath << std::endl; filepath path(relpath); InodeRef in; - int r = path_walk(path, &in, true, mask); + int r = path_walk(path, &in, perms, true, mask); if (r < 0) return r; - r = _getattr(in, mask); + r = _getattr(in, mask, perms); if (r < 0) { ldout(cct, 3) << "stat exit on error!" << dendl; return r; @@ -6737,6 +6715,7 @@ unsigned Client::statx_to_mask(unsigned int flags, unsigned int want) } int Client::statx(const char *relpath, struct ceph_statx *stx, + const UserPerm& perms, unsigned int want, unsigned int flags) { ldout(cct, 3) << "statx enter (relpath " << relpath << " want " << want << ")" << dendl; @@ -6748,12 +6727,12 @@ int Client::statx(const char *relpath, struct ceph_statx *stx, unsigned mask = statx_to_mask(flags, want); - int r = path_walk(path, &in, flags & AT_SYMLINK_NOFOLLOW, mask); + int r = path_walk(path, &in, perms, flags & AT_SYMLINK_NOFOLLOW, mask); if (r < 0) return r; if (mask && !in->caps_issued_mask(mask)) { - r = _getattr(in, mask); + r = _getattr(in, mask, perms); if (r < 0) { ldout(cct, 3) << "statx exit on error!" << dendl; return r; @@ -6766,7 +6745,7 @@ int Client::statx(const char *relpath, struct ceph_statx *stx, } int Client::lstat(const char *relpath, struct stat *stbuf, - frag_info_t *dirstat, int mask) + const UserPerm& perms, frag_info_t *dirstat, int mask) { ldout(cct, 3) << "lstat enter (relpath " << relpath << " mask " << mask << ")" << dendl; Mutex::Locker lock(client_lock); @@ -6775,10 +6754,10 @@ int Client::lstat(const char *relpath, struct stat *stbuf, filepath path(relpath); InodeRef in; // don't follow symlinks - int r = path_walk(path, &in, false, mask); + int r = path_walk(path, &in, perms, false, mask); if (r < 0) return r; - r = _getattr(in, mask); + r = _getattr(in, mask, perms); if (r < 0) { ldout(cct, 3) << "lstat exit on error!" << dendl; return r; @@ -6905,7 +6884,7 @@ void Client::touch_dn(Dentry *dn) lru.lru_touch(dn); } -int Client::chmod(const char *relpath, mode_t mode) +int Client::chmod(const char *relpath, mode_t mode, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "chmod" << std::endl; @@ -6913,15 +6892,15 @@ int Client::chmod(const char *relpath, mode_t mode) tout(cct) << mode << std::endl; filepath path(relpath); InodeRef in; - int r = path_walk(path, &in); + int r = path_walk(path, &in, perms); if (r < 0) return r; struct stat attr; attr.st_mode = mode; - return _setattr(in, &attr, CEPH_SETATTR_MODE); + return _setattr(in, &attr, CEPH_SETATTR_MODE, perms); } -int Client::fchmod(int fd, mode_t mode) +int Client::fchmod(int fd, mode_t mode, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "fchmod" << std::endl; @@ -6936,10 +6915,10 @@ int Client::fchmod(int fd, mode_t mode) #endif struct stat attr; attr.st_mode = mode; - return _setattr(f->inode, &attr, CEPH_SETATTR_MODE); + return _setattr(f->inode, &attr, CEPH_SETATTR_MODE, perms); } -int Client::lchmod(const char *relpath, mode_t mode) +int Client::lchmod(const char *relpath, mode_t mode, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "lchmod" << std::endl; @@ -6948,42 +6927,43 @@ int Client::lchmod(const char *relpath, mode_t mode) filepath path(relpath); InodeRef in; // don't follow symlinks - int r = path_walk(path, &in, false); + int r = path_walk(path, &in, perms, false); if (r < 0) return r; struct stat attr; attr.st_mode = mode; - return _setattr(in, &attr, CEPH_SETATTR_MODE); + return _setattr(in, &attr, CEPH_SETATTR_MODE, perms); } -int Client::chown(const char *relpath, int uid, int gid) +int Client::chown(const char *relpath, uid_t new_uid, gid_t new_gid, + const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "chown" << std::endl; tout(cct) << relpath << std::endl; - tout(cct) << uid << std::endl; - tout(cct) << gid << std::endl; + tout(cct) << new_uid << std::endl; + tout(cct) << new_gid << std::endl; filepath path(relpath); InodeRef in; - int r = path_walk(path, &in); + int r = path_walk(path, &in, perms); if (r < 0) return r; struct stat attr; - attr.st_uid = uid; - attr.st_gid = gid; + attr.st_uid = new_uid; + attr.st_gid = new_gid; int mask = 0; - if (uid != -1) mask |= CEPH_SETATTR_UID; - if (gid != -1) mask |= CEPH_SETATTR_GID; - return _setattr(in, &attr, mask); + if (new_uid != static_cast(-1)) mask |= CEPH_SETATTR_UID; + if (new_gid != static_cast(-1)) mask |= CEPH_SETATTR_GID; + return _setattr(in, &attr, mask, perms); } -int Client::fchown(int fd, int uid, int gid) +int Client::fchown(int fd, uid_t new_uid, gid_t new_gid, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "fchown" << std::endl; tout(cct) << fd << std::endl; - tout(cct) << uid << std::endl; - tout(cct) << gid << std::endl; + tout(cct) << new_uid << std::endl; + tout(cct) << new_gid << std::endl; Fh *f = get_filehandle(fd); if (!f) return -EBADF; @@ -6992,37 +6972,39 @@ int Client::fchown(int fd, int uid, int gid) return -EBADF; #endif struct stat attr; - attr.st_uid = uid; - attr.st_gid = gid; + attr.st_uid = new_uid; + attr.st_gid = new_gid; int mask = 0; - if (uid != -1) mask |= CEPH_SETATTR_UID; - if (gid != -1) mask |= CEPH_SETATTR_GID; - return _setattr(f->inode, &attr, mask); + if (new_uid != static_cast(-1)) mask |= CEPH_SETATTR_UID; + if (new_gid != static_cast(-1)) mask |= CEPH_SETATTR_GID; + return _setattr(f->inode, &attr, mask, perms); } -int Client::lchown(const char *relpath, int uid, int gid) +int Client::lchown(const char *relpath, uid_t new_uid, gid_t new_gid, + const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "lchown" << std::endl; tout(cct) << relpath << std::endl; - tout(cct) << uid << std::endl; - tout(cct) << gid << std::endl; + tout(cct) << new_uid << std::endl; + tout(cct) << new_gid << std::endl; filepath path(relpath); InodeRef in; // don't follow symlinks - int r = path_walk(path, &in, false); + int r = path_walk(path, &in, perms, false); if (r < 0) return r; struct stat attr; - attr.st_uid = uid; - attr.st_gid = gid; + attr.st_uid = new_uid; + attr.st_gid = new_gid; int mask = 0; - if (uid != -1) mask |= CEPH_SETATTR_UID; - if (gid != -1) mask |= CEPH_SETATTR_GID; - return _setattr(in, &attr, mask); + if (new_uid != static_cast(-1)) mask |= CEPH_SETATTR_UID; + if (new_gid != static_cast(-1)) mask |= CEPH_SETATTR_GID; + return _setattr(in, &attr, mask, perms); } -int Client::utime(const char *relpath, struct utimbuf *buf) +int Client::utime(const char *relpath, struct utimbuf *buf, + const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "utime" << std::endl; @@ -7031,7 +7013,7 @@ int Client::utime(const char *relpath, struct utimbuf *buf) tout(cct) << buf->actime << std::endl; filepath path(relpath); InodeRef in; - int r = path_walk(path, &in); + int r = path_walk(path, &in, perms); if (r < 0) return r; struct stat attr; @@ -7039,10 +7021,11 @@ int Client::utime(const char *relpath, struct utimbuf *buf) stat_set_mtime_nsec(&attr, 0); stat_set_atime_sec(&attr, buf->actime); stat_set_atime_nsec(&attr, 0); - return _setattr(in, &attr, CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME); + return _setattr(in, &attr, CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME, perms); } -int Client::lutime(const char *relpath, struct utimbuf *buf) +int Client::lutime(const char *relpath, struct utimbuf *buf, + const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "lutime" << std::endl; @@ -7052,7 +7035,7 @@ int Client::lutime(const char *relpath, struct utimbuf *buf) filepath path(relpath); InodeRef in; // don't follow symlinks - int r = path_walk(path, &in, false); + int r = path_walk(path, &in, perms, false); if (r < 0) return r; struct stat attr; @@ -7060,7 +7043,7 @@ int Client::lutime(const char *relpath, struct utimbuf *buf) stat_set_mtime_nsec(&attr, 0); stat_set_atime_sec(&attr, buf->actime); stat_set_atime_nsec(&attr, 0); - return _setattr(in, &attr, CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME); + return _setattr(in, &attr, CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME, perms); } int Client::flock(int fd, int operation, uint64_t owner) @@ -7077,34 +7060,32 @@ int Client::flock(int fd, int operation, uint64_t owner) return _flock(f, operation, owner); } -int Client::opendir(const char *relpath, dir_result_t **dirpp) +int Client::opendir(const char *relpath, dir_result_t **dirpp, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "opendir" << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); InodeRef in; - int r = path_walk(path, &in); + int r = path_walk(path, &in, perms, true); if (r < 0) return r; if (cct->_conf->client_permissions) { - int r = may_open(in.get(), O_RDONLY); + int r = may_open(in.get(), O_RDONLY, perms); if (r < 0) return r; } - r = _opendir(in.get(), dirpp); + r = _opendir(in.get(), dirpp, perms); tout(cct) << (unsigned long)*dirpp << std::endl; return r; } -int Client::_opendir(Inode *in, dir_result_t **dirpp, int uid, int gid) +int Client::_opendir(Inode *in, dir_result_t **dirpp, const UserPerm& perms) { if (!in->is_dir()) return -ENOTDIR; - *dirpp = new dir_result_t(in); + *dirpp = new dir_result_t(in, perms); opened_dirs.insert(*dirpp); - (*dirpp)->owner_uid = uid; - (*dirpp)->owner_gid = gid; ldout(cct, 3) << "_opendir(" << in->ino << ") = " << 0 << " (" << *dirpp << ")" << dendl; return 0; } @@ -7288,7 +7269,7 @@ int Client::_readdir_get_frag(dir_result_t *dirp) req->dirp = dirp; bufferlist dirbl; - int res = make_request(req, dirp->owner_uid, dirp->owner_gid, NULL, NULL, -1, &dirbl); + int res = make_request(req, dirp->perms, NULL, NULL, -1, &dirbl); if (res == -EAGAIN) { ldout(cct, 10) << "_readdir_get_frag got EAGAIN, retrying" << dendl; @@ -7687,7 +7668,8 @@ static int _getdir_cb(void *p, struct dirent *de, struct stat *st, int stmask, o return 0; } -int Client::getdir(const char *relpath, list& contents) +int Client::getdir(const char *relpath, list& contents, + const UserPerm& perms) { ldout(cct, 3) << "getdir(" << relpath << ")" << dendl; { @@ -7697,7 +7679,7 @@ int Client::getdir(const char *relpath, list& contents) } dir_result_t *d; - int r = opendir(relpath, &d); + int r = opendir(relpath, &d, perms); if (r < 0) return r; @@ -7715,8 +7697,9 @@ int Client::getdir(const char *relpath, list& contents) /****** file i/o **********/ -int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, - int stripe_count, int object_size, const char *data_pool) +int Client::open(const char *relpath, int flags, const UserPerm& perms, + mode_t mode, int stripe_unit, int stripe_count, + int object_size, const char *data_pool) { ldout(cct, 3) << "open enter(" << relpath << ", " << flags << "," << mode << ") = " << dendl; Mutex::Locker lock(client_lock); @@ -7724,9 +7707,6 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, tout(cct) << relpath << std::endl; tout(cct) << flags << std::endl; - uid_t uid = get_uid(); - gid_t gid = get_gid(); - Fh *fh = NULL; #if defined(__linux__) && defined(O_PATH) @@ -7742,7 +7722,7 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, bool created = false; /* O_CREATE with O_EXCL enforces O_NOFOLLOW. */ bool followsym = !((flags & O_NOFOLLOW) || ((flags & O_CREAT) && (flags & O_EXCL))); - int r = path_walk(path, &in, followsym, ceph_caps_for_mode(mode), uid, gid); + int r = path_walk(path, &in, perms, followsym, ceph_caps_for_mode(mode)); if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL)) return -EEXIST; @@ -7759,18 +7739,17 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, string dname = dirpath.last_dentry(); dirpath.pop_dentry(); InodeRef dir; - r = path_walk(dirpath, &dir, true, - cct->_conf->client_permissions ? CEPH_CAP_AUTH_SHARED : 0, - uid, gid); + r = path_walk(dirpath, &dir, perms, true, + cct->_conf->client_permissions ? CEPH_CAP_AUTH_SHARED : 0); if (r < 0) goto out; if (cct->_conf->client_permissions) { - r = may_create(dir.get(), uid, gid); + r = may_create(dir.get(), perms); if (r < 0) goto out; } r = _create(dir.get(), dname.c_str(), flags, mode, &in, &fh, stripe_unit, - stripe_count, object_size, data_pool, &created, uid, gid); + stripe_count, object_size, data_pool, &created, perms); } if (r < 0) goto out; @@ -7778,14 +7757,14 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, if (!created) { // posix says we can only check permissions of existing files if (cct->_conf->client_permissions) { - r = may_open(in.get(), flags, uid, gid); + r = may_open(in.get(), flags, perms); if (r < 0) goto out; } } if (!fh) - r = _open(in.get(), flags, mode, &fh, uid, gid); + r = _open(in.get(), flags, mode, &fh, perms); if (r >= 0) { // allocate a integer file descriptor assert(fh); @@ -7800,13 +7779,14 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, return r; } -int Client::open(const char *relpath, int flags, mode_t mode) +int Client::open(const char *relpath, int flags, const UserPerm& perms, mode_t mode) { /* Use default file striping parameters */ - return open(relpath, flags, mode, 0, 0, 0, NULL); + return open(relpath, flags, perms, mode, 0, 0, 0, NULL); } -int Client::lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name) +int Client::lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name, + const UserPerm& perms) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "lookup_hash enter(" << ino << ", #" << dirino << "/" << name << ") = " << dendl; @@ -7822,7 +7802,8 @@ int Client::lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name) path2.push_dentry(string(f)); req->set_filepath2(path2); - int r = make_request(req, -1, -1, NULL, NULL, rand() % mdsmap->get_num_in_mds()); + int r = make_request(req, perms, NULL, NULL, + rand() % mdsmap->get_num_in_mds()); ldout(cct, 3) << "lookup_hash exit(" << ino << ", #" << dirino << "/" << name << ") = " << r << dendl; return r; } @@ -7835,7 +7816,7 @@ int Client::lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name) * the resulting Inode object in one operation, so that caller * can safely assume inode will still be there after return. */ -int Client::lookup_ino(inodeno_t ino, Inode **inode) +int Client::lookup_ino(inodeno_t ino, const UserPerm& perms, Inode **inode) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "lookup_ino enter(" << ino << ") = " << dendl; @@ -7844,7 +7825,7 @@ int Client::lookup_ino(inodeno_t ino, Inode **inode) filepath path(ino); req->set_filepath(path); - int r = make_request(req, -1, -1, NULL, NULL, rand() % mdsmap->get_num_in_mds()); + int r = make_request(req, perms, NULL, NULL, rand() % mdsmap->get_num_in_mds()); if (r == 0 && inode != NULL) { vinodeno_t vino(ino, CEPH_NOSNAP); unordered_map::iterator p = inode_map.find(vino); @@ -7863,12 +7844,14 @@ int Client::lookup_ino(inodeno_t ino, Inode **inode) * our cache. Conditionally also set `parent` to a referenced * Inode* if caller provides non-NULL value. */ -int Client::lookup_parent(Inode *ino, Inode **parent) +int Client::lookup_parent(Inode *ino, const UserPerm& perms, Inode **parent) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "lookup_parent enter(" << ino->ino << ") = " << dendl; if (!ino->dn_set.empty()) { + // if we exposed the parent here, we'd need to check permissions, + // but right now we just rely on the MDS doing so in make_request ldout(cct, 3) << "lookup_parent dentry already present" << dendl; return 0; } @@ -7879,7 +7862,7 @@ int Client::lookup_parent(Inode *ino, Inode **parent) req->set_inode(ino); InodeRef target; - int r = make_request(req, -1, -1, &target, NULL, rand() % mdsmap->get_num_in_mds()); + int r = make_request(req, perms, &target, NULL, rand() % mdsmap->get_num_in_mds()); // Give caller a reference to the parent ino if they provided a pointer. if (parent != NULL) { if (r == 0) { @@ -7899,7 +7882,7 @@ int Client::lookup_parent(Inode *ino, Inode **parent) * Populate the parent dentry for `ino`, provided it is * a child of `parent`. */ -int Client::lookup_name(Inode *ino, Inode *parent) +int Client::lookup_name(Inode *ino, Inode *parent, const UserPerm& perms) { assert(parent->is_dir()); @@ -7911,13 +7894,13 @@ int Client::lookup_name(Inode *ino, Inode *parent) req->set_filepath(filepath(ino->ino)); req->set_inode(ino); - int r = make_request(req, -1, -1, NULL, NULL, rand() % mdsmap->get_num_in_mds()); + int r = make_request(req, perms, NULL, NULL, rand() % mdsmap->get_num_in_mds()); ldout(cct, 3) << "lookup_name exit(" << ino->ino << ") = " << r << dendl; return r; } -Fh *Client::_create_fh(Inode *in, int flags, int cmode) + Fh *Client::_create_fh(Inode *in, int flags, int cmode, const UserPerm& perms) { // yay Fh *f = new Fh; @@ -7927,6 +7910,7 @@ Fh *Client::_create_fh(Inode *in, int flags, int cmode) // inode assert(in); f->inode = in; + f->actor_perms = perms; ldout(cct, 10) << "_create_fh " << in->ino << " mode " << cmode << dendl; @@ -7995,7 +7979,8 @@ void Client::_put_fh(Fh *f) delete f; } -int Client::_open(Inode *in, int flags, mode_t mode, Fh **fhp, int uid, int gid) +int Client::_open(Inode *in, int flags, mode_t mode, Fh **fhp, + const UserPerm& perms) { int cmode = ceph_flags_to_mode(flags); if (cmode < 0) @@ -8028,13 +8013,13 @@ int Client::_open(Inode *in, int flags, mode_t mode, Fh **fhp, int uid, int gid) req->head.args.open.mask = 0; req->head.args.open.old_size = in->size; // for O_TRUNC req->set_inode(in); - result = make_request(req, uid, gid); + result = make_request(req, perms); } // success? if (result >= 0) { if (fhp) - *fhp = _create_fh(in, flags, cmode); + *fhp = _create_fh(in, flags, cmode, perms); } else { in->put_open_ref(cmode); } @@ -8073,7 +8058,12 @@ int Client::_renew_caps(Inode *in) req->head.args.open.mask = 0; req->set_inode(in); - int ret = make_request(req, -1, -1); + // duplicate in case Cap goes away; not sure if that race is a concern? + const UserPerm *pperm = in->get_best_perms(); + UserPerm perms; + if (pperm != NULL) + perms = *pperm; + int ret = make_request(req, perms); return ret; } @@ -8098,7 +8088,7 @@ int Client::close(int fd) // ------------ // read, write -loff_t Client::lseek(int fd, loff_t offset, int whence) +loff_t Client::lseek(int fd, loff_t offset, int whence, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "lseek" << std::endl; @@ -8113,14 +8103,18 @@ loff_t Client::lseek(int fd, loff_t offset, int whence) if (f->flags & O_PATH) return -EBADF; #endif - return _lseek(f, offset, whence); + return _lseek(f, offset, whence, perms); } -loff_t Client::_lseek(Fh *f, loff_t offset, int whence) +loff_t Client::_lseek(Fh *f, loff_t offset, int whence, const UserPerm& perms) { Inode *in = f->inode.get(); int r; + if (!may_open(f->inode.get(), f->flags, perms)) { + return -EPERM; + } + switch (whence) { case SEEK_SET: f->pos = offset; @@ -8131,7 +8125,7 @@ loff_t Client::_lseek(Fh *f, loff_t offset, int whence) break; case SEEK_END: - r = _getattr(in, CEPH_STAT_CAP_SIZE); + r = _getattr(in, CEPH_STAT_CAP_SIZE, perms); if (r < 0) return r; f->pos = in->size + offset; @@ -8271,7 +8265,7 @@ int Client::_read(Fh *f, int64_t offset, uint64_t size, bufferlist *bl) loff_t start_pos = offset; if (in->inline_version == 0) { - int r = _getattr(in, CEPH_STAT_CAP_INLINE_DATA, -1, -1, true); + int r = _getattr(in, CEPH_STAT_CAP_INLINE_DATA, f->actor_perms, true); if (r < 0) return r; assert(in->inline_version > 0); @@ -8345,7 +8339,7 @@ int Client::_read(Fh *f, int64_t offset, uint64_t size, bufferlist *bl) put_cap_ref(in, CEPH_CAP_FILE_RD); have = 0; // reverify size - r = _getattr(in, CEPH_STAT_CAP_SIZE); + r = _getattr(in, CEPH_STAT_CAP_SIZE, f->actor_perms); if (r < 0) goto done; @@ -8665,8 +8659,10 @@ int Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf, // check quota uint64_t endoff = offset + size; - if (endoff > in->size && is_quota_bytes_exceeded(in, endoff - in->size)) + if (endoff > in->size && is_quota_bytes_exceeded(in, endoff - in->size, + f->actor_perms)) { return -EDQUOT; + } // use/adjust fd pos? if (offset < 0) { @@ -8676,7 +8672,7 @@ int Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf, * change out from under us. */ if (f->flags & O_APPEND) { - int r = _lseek(f, 0, SEEK_END); + int r = _lseek(f, 0, SEEK_END, f->actor_perms); if (r < 0) { unlock_fh_pos(f); return r; @@ -8695,7 +8691,7 @@ int Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf, utime_t start = ceph_clock_now(cct); if (in->inline_version == 0) { - int r = _getattr(in, CEPH_STAT_CAP_INLINE_DATA, -1, -1, true); + int r = _getattr(in, CEPH_STAT_CAP_INLINE_DATA, f->actor_perms, true); if (r < 0) return r; assert(in->inline_version > 0); @@ -8835,7 +8831,7 @@ int Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf, in->size = totalwritten + offset; mark_caps_dirty(in, CEPH_CAP_FILE_WR); - if (is_quota_bytes_approaching(in)) { + if (is_quota_bytes_approaching(in, f->actor_perms)) { check_caps(in, true); } else { if ((in->size << 1) >= in->max_size && @@ -8891,14 +8887,14 @@ int Client::_flush(Fh *f) return err; } -int Client::truncate(const char *relpath, loff_t length) +int Client::truncate(const char *relpath, loff_t length, const UserPerm& perms) { struct ceph_statx stx; stx.stx_size = length; - return setattrx(relpath, &stx, CEPH_SETATTR_SIZE); + return setattrx(relpath, &stx, CEPH_SETATTR_SIZE, perms); } -int Client::ftruncate(int fd, loff_t length) +int Client::ftruncate(int fd, loff_t length, const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "ftruncate" << std::endl; @@ -8914,7 +8910,7 @@ int Client::ftruncate(int fd, loff_t length) #endif struct stat attr; attr.st_size = length; - return _setattr(f->inode, &attr, CEPH_SETATTR_SIZE); + return _setattr(f->inode, &attr, CEPH_SETATTR_SIZE, perms); } int Client::fsync(int fd, bool syncdataonly) @@ -9013,7 +9009,7 @@ int Client::_fsync(Fh *f, bool syncdataonly) return _fsync(f->inode.get(), syncdataonly); } -int Client::fstat(int fd, struct stat *stbuf, int mask) +int Client::fstat(int fd, struct stat *stbuf, const UserPerm& perms, int mask) { Mutex::Locker lock(client_lock); tout(cct) << "fstat mask " << hex << mask << dec << std::endl; @@ -9022,7 +9018,7 @@ int Client::fstat(int fd, struct stat *stbuf, int mask) Fh *f = get_filehandle(fd); if (!f) return -EBADF; - int r = _getattr(f->inode, mask); + int r = _getattr(f->inode, mask, perms); if (r < 0) return r; fill_stat(f->inode, stbuf, NULL); @@ -9030,7 +9026,8 @@ int Client::fstat(int fd, struct stat *stbuf, int mask) return r; } -int Client::fstatx(int fd, struct ceph_statx *stx, unsigned int want, unsigned int flags) +int Client::fstatx(int fd, struct ceph_statx *stx, const UserPerm& perms, + unsigned int want, unsigned int flags) { Mutex::Locker lock(client_lock); tout(cct) << "fstatx flags " << hex << flags << " want " << want << dec << std::endl; @@ -9044,7 +9041,7 @@ int Client::fstatx(int fd, struct ceph_statx *stx, unsigned int want, unsigned i int r = 0; if (mask && !f->inode->caps_issued_mask(mask)) { - r = _getattr(f->inode, mask); + r = _getattr(f->inode, mask, perms); if (r < 0) { ldout(cct, 3) << "fstatx exit on error!" << dendl; return r; @@ -9058,25 +9055,26 @@ int Client::fstatx(int fd, struct ceph_statx *stx, unsigned int want, unsigned i // not written yet, but i want to link! -int Client::chdir(const char *relpath, std::string &new_cwd) +int Client::chdir(const char *relpath, std::string &new_cwd, + const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "chdir" << std::endl; tout(cct) << relpath << std::endl; filepath path(relpath); InodeRef in; - int r = path_walk(path, &in); + int r = path_walk(path, &in, perms); if (r < 0) return r; if (cwd != in) cwd.swap(in); ldout(cct, 3) << "chdir(" << relpath << ") cwd now " << cwd->ino << dendl; - getcwd(new_cwd); + getcwd(new_cwd, perms); return 0; } -void Client::getcwd(string& dir) +void Client::getcwd(string& dir, const UserPerm& perms) { filepath path; ldout(cct, 10) << "getcwd " << *cwd << dendl; @@ -9100,7 +9098,7 @@ void Client::getcwd(string& dir) filepath path(in->ino); req->set_filepath(path); req->set_inode(in); - int res = make_request(req, -1, -1); + int res = make_request(req, perms); if (res < 0) break; @@ -9116,7 +9114,8 @@ void Client::getcwd(string& dir) dir += path.get_path(); } -int Client::statfs(const char *path, struct statvfs *stbuf) +int Client::statfs(const char *path, struct statvfs *stbuf, + const UserPerm& perms) { Mutex::Locker l(client_lock); tout(cct) << "statfs" << std::endl; @@ -9159,7 +9158,7 @@ int Client::statfs(const char *path, struct statvfs *stbuf) // quota but we can see a parent of it that does have a quota, we'll // respect that one instead. assert(root != nullptr); - Inode *quota_root = root->quota.is_enable() ? root : get_quota_root(root); + Inode *quota_root = root->quota.is_enable() ? root : get_quota_root(root, perms); // get_quota_root should always give us something if client quotas are // enabled @@ -9190,7 +9189,7 @@ int Client::statfs(const char *path, struct statvfs *stbuf) } int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, - struct flock *fl, uint64_t owner) + struct flock *fl, uint64_t owner, bool removing) { ldout(cct, 10) << "_do_filelock ino " << in->ino << (lock_type == CEPH_LOCK_FCNTL ? " fcntl" : " flock") @@ -9237,14 +9236,13 @@ int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, if (sleep && switch_interrupt_cb) { // enable interrupt switch_interrupt_cb(callback_handle, req->get()); - - ret = make_request(req, -1, -1, NULL, NULL, -1, &bl); + ret = make_request(req, fh->actor_perms, NULL, NULL, -1, &bl); // disable interrupt switch_interrupt_cb(callback_handle, NULL); put_request(req); } else { - ret = make_request(req, -1, -1, NULL, NULL, -1, &bl); + ret = make_request(req, fh->actor_perms, NULL, NULL, -1, &bl); } if (ret == 0) { @@ -9280,7 +9278,7 @@ int Client::_do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, } _update_lock_state(fl, owner, lock_state); - if (fh) { + if (!removing) { if (lock_type == CEPH_LOCK_FCNTL) { if (!fh->fcntl_locks) fh->fcntl_locks = new ceph_lock_state_t(cct, CEPH_LOCK_FCNTL); @@ -9321,7 +9319,8 @@ int Client::_interrupt_filelock(MetaRequest *req) intr_req->head.args.filelock_change.rule = lock_type; intr_req->head.args.filelock_change.type = CEPH_LOCK_UNLOCK; - return make_request(intr_req, -1, -1, NULL, NULL, -1); + UserPerm perms(req->get_uid(), req->get_gid()); + return make_request(intr_req, perms, NULL, NULL, -1); } void Client::_encode_filelocks(Inode *in, bufferlist& bl) @@ -9394,7 +9393,8 @@ void Client::_release_filelocks(Fh *fh) fl.l_start = p->second.start; fl.l_len = p->second.length; fl.l_pid = p->second.pid; - _do_filelock(in, NULL, p->first, CEPH_MDS_OP_SETFILELOCK, 0, &fl, p->second.owner); + _do_filelock(in, fh, p->first, CEPH_MDS_OP_SETFILELOCK, 0, &fl, + p->second.owner, true); } } @@ -9477,12 +9477,12 @@ int Client::_flock(Fh *fh, int cmd, uint64_t owner) return ret; } -int Client::ll_statfs(Inode *in, struct statvfs *stbuf) +int Client::ll_statfs(Inode *in, struct statvfs *stbuf, const UserPerm& perms) { /* Since the only thing this does is wrap a call to statfs, and statfs takes a lock, it doesn't seem we have a need to split it out. */ - return statfs(0, stbuf); + return statfs(0, stbuf, perms); } void Client::ll_register_callbacks(struct client_callback_args *args) @@ -9631,37 +9631,37 @@ int Client::lazyio_synchronize(int fd, loff_t offset, size_t count) // ============================= // snaps -int Client::mksnap(const char *relpath, const char *name) +int Client::mksnap(const char *relpath, const char *name, const UserPerm& perm) { Mutex::Locker l(client_lock); filepath path(relpath); InodeRef in; - int r = path_walk(path, &in); + int r = path_walk(path, &in, perm); if (r < 0) return r; if (cct->_conf->client_permissions) { - r = may_create(in.get()); + r = may_create(in.get(), perm); if (r < 0) return r; } Inode *snapdir = open_snapdir(in.get()); - return _mkdir(snapdir, name, 0); + return _mkdir(snapdir, name, 0, perm); } -int Client::rmsnap(const char *relpath, const char *name) +int Client::rmsnap(const char *relpath, const char *name, const UserPerm& perms) { Mutex::Locker l(client_lock); filepath path(relpath); InodeRef in; - int r = path_walk(path, &in); + int r = path_walk(path, &in, perms); if (r < 0) return r; if (cct->_conf->client_permissions) { - r = may_delete(in.get(), NULL); + r = may_delete(in.get(), NULL, perms); if (r < 0) return r; } Inode *snapdir = open_snapdir(in.get()); - return _rmdir(snapdir, name); + return _rmdir(snapdir, name, perms); } // ============================= @@ -9678,12 +9678,12 @@ int Client::get_caps_issued(int fd) { return f->inode->caps_issued(); } -int Client::get_caps_issued(const char *path) { - +int Client::get_caps_issued(const char *path, const UserPerm& perms) +{ Mutex::Locker lock(client_lock); filepath p(path); InodeRef in; - int r = path_walk(p, &in, true); + int r = path_walk(p, &in, perms, true); if (r < 0) return r; return in->caps_issued(); @@ -9725,7 +9725,7 @@ Inode *Client::open_snapdir(Inode *diri) } int Client::ll_lookup(Inode *parent, const char *name, struct stat *attr, - Inode **out, int uid, int gid) + Inode **out, const UserPerm& perms) { Mutex::Locker lock(client_lock); ldout(cct, 3) << "ll_lookup " << parent << " " << name << dendl; @@ -9734,7 +9734,7 @@ int Client::ll_lookup(Inode *parent, const char *name, struct stat *attr, int r = 0; if (!cct->_conf->fuse_default_permissions) { - r = may_lookup(parent, uid, gid); + r = may_lookup(parent, perms); if (r < 0) return r; } @@ -9742,7 +9742,7 @@ int Client::ll_lookup(Inode *parent, const char *name, struct stat *attr, string dname(name); InodeRef in; - r = _lookup(parent, dname, CEPH_STAT_CAP_INODE_ALL, &in, uid, gid); + r = _lookup(parent, dname, CEPH_STAT_CAP_INODE_ALL, &in, perms); if (r < 0) { attr->st_ino = 0; goto out; @@ -9760,7 +9760,8 @@ int Client::ll_lookup(Inode *parent, const char *name, struct stat *attr, return r; } -int Client::ll_walk(const char* name, Inode **out, struct stat *attr) +int Client::ll_walk(const char* name, Inode **out, struct stat *attr, + const UserPerm& perms) { Mutex::Locker lock(client_lock); filepath fp(name, 0); @@ -9771,7 +9772,7 @@ int Client::ll_walk(const char* name, Inode **out, struct stat *attr) tout(cct) << "ll_walk" << std::endl; tout(cct) << name << std::endl; - rc = path_walk(fp, &in, false, CEPH_STAT_CAP_INODE_ALL); + rc = path_walk(fp, &in, perms, false, CEPH_STAT_CAP_INODE_ALL); if (rc < 0) { attr->st_ino = 0; *out = NULL; @@ -9890,7 +9891,7 @@ Inode *Client::ll_get_inode(vinodeno_t vino) return in; } -int Client::_ll_getattr(Inode *in, int uid, int gid) +int Client::_ll_getattr(Inode *in, const UserPerm& perms) { vinodeno_t vino = _get_vino(in); @@ -9901,14 +9902,14 @@ int Client::_ll_getattr(Inode *in, int uid, int gid) if (vino.snapid < CEPH_NOSNAP) return 0; else - return _getattr(in, CEPH_STAT_CAP_INODE_ALL, uid, gid); + return _getattr(in, CEPH_STAT_CAP_INODE_ALL, perms); } -int Client::ll_getattr(Inode *in, struct stat *attr, int uid, int gid) +int Client::ll_getattr(Inode *in, struct stat *attr, const UserPerm& perms) { Mutex::Locker lock(client_lock); - int res = _ll_getattr(in, uid, gid); + int res = _ll_getattr(in, perms); if (res == 0) fill_stat(in, attr); @@ -9917,7 +9918,7 @@ int Client::ll_getattr(Inode *in, struct stat *attr, int uid, int gid) } int Client::ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want, - unsigned int flags, int uid, int gid) + unsigned int flags, const UserPerm& perms) { Mutex::Locker lock(client_lock); @@ -9925,7 +9926,7 @@ int Client::ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want, unsigned mask = statx_to_mask(flags, want); if (mask && !in->caps_issued_mask(mask)) - res = _ll_getattr(in, uid, gid); + res = _ll_getattr(in, perms); if (res == 0) fill_statx(in, mask, stx); @@ -9933,8 +9934,8 @@ int Client::ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want, return res; } -int Client::_ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid, - int gid, InodeRef *inp) +int Client::_ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms, InodeRef *inp) { Mutex::Locker lock(client_lock); @@ -9954,21 +9955,21 @@ int Client::_ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid, tout(cct) << mask << std::endl; if (!cct->_conf->fuse_default_permissions) { - int res = may_setattr(in, stx, mask, uid, gid); + int res = may_setattr(in, stx, mask, perms); if (res < 0) return res; } mask &= ~(CEPH_SETATTR_MTIME_NOW | CEPH_SETATTR_ATIME_NOW); - return __setattrx(in, stx, mask, uid, gid, inp); + return __setattrx(in, stx, mask, perms, inp); } -int Client::ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid, - int gid) +int Client::ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms) { InodeRef target(in); - int res = _ll_setattrx(in, stx, mask, uid, gid, &target); + int res = _ll_setattrx(in, stx, mask, perms, &target); if (res == 0) { assert(in == target.get()); fill_statx(in, in->caps_issued(), stx); @@ -9978,15 +9979,15 @@ int Client::ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid, return res; } -int Client::ll_setattr(Inode *in, struct stat *attr, int mask, int uid, - int gid) +int Client::ll_setattr(Inode *in, struct stat *attr, int mask, + const UserPerm& perms) { struct ceph_statx stx; stat_to_statx(attr, &stx); InodeRef target(in); - int res = _ll_setattrx(in, &stx, mask, uid, gid, &target); + int res = _ll_setattrx(in, &stx, mask, perms, &target); if (res == 0) { assert(in == target.get()); fill_stat(in, attr); @@ -10000,124 +10001,134 @@ int Client::ll_setattr(Inode *in, struct stat *attr, int mask, int uid, // ---------- // xattrs -int Client::getxattr(const char *path, const char *name, void *value, size_t size) +int Client::getxattr(const char *path, const char *name, void *value, size_t size, + const UserPerm& perms) { Mutex::Locker lock(client_lock); InodeRef in; - int r = Client::path_walk(path, &in, true, CEPH_STAT_CAP_XATTR); + int r = Client::path_walk(path, &in, perms, true, CEPH_STAT_CAP_XATTR); if (r < 0) return r; - return _getxattr(in, name, value, size); + return _getxattr(in, name, value, size, perms); } -int Client::lgetxattr(const char *path, const char *name, void *value, size_t size) +int Client::lgetxattr(const char *path, const char *name, void *value, size_t size, + const UserPerm& perms) { Mutex::Locker lock(client_lock); InodeRef in; - int r = Client::path_walk(path, &in, false, CEPH_STAT_CAP_XATTR); + int r = Client::path_walk(path, &in, perms, false, CEPH_STAT_CAP_XATTR); if (r < 0) return r; - return _getxattr(in, name, value, size); + return _getxattr(in, name, value, size, perms); } -int Client::fgetxattr(int fd, const char *name, void *value, size_t size) +int Client::fgetxattr(int fd, const char *name, void *value, size_t size, + const UserPerm& perms) { Mutex::Locker lock(client_lock); Fh *f = get_filehandle(fd); if (!f) return -EBADF; - return _getxattr(f->inode, name, value, size); + return _getxattr(f->inode, name, value, size, perms); } -int Client::listxattr(const char *path, char *list, size_t size) +int Client::listxattr(const char *path, char *list, size_t size, + const UserPerm& perms) { Mutex::Locker lock(client_lock); InodeRef in; - int r = Client::path_walk(path, &in, true, CEPH_STAT_CAP_XATTR); + int r = Client::path_walk(path, &in, perms, true, CEPH_STAT_CAP_XATTR); if (r < 0) return r; - return Client::_listxattr(in.get(), list, size); + return Client::_listxattr(in.get(), list, size, perms); } -int Client::llistxattr(const char *path, char *list, size_t size) +int Client::llistxattr(const char *path, char *list, size_t size, + const UserPerm& perms) { Mutex::Locker lock(client_lock); InodeRef in; - int r = Client::path_walk(path, &in, false, CEPH_STAT_CAP_XATTR); + int r = Client::path_walk(path, &in, perms, false, CEPH_STAT_CAP_XATTR); if (r < 0) return r; - return Client::_listxattr(in.get(), list, size); + return Client::_listxattr(in.get(), list, size, perms); } -int Client::flistxattr(int fd, char *list, size_t size) +int Client::flistxattr(int fd, char *list, size_t size, const UserPerm& perms) { Mutex::Locker lock(client_lock); Fh *f = get_filehandle(fd); if (!f) return -EBADF; - return Client::_listxattr(f->inode.get(), list, size); + return Client::_listxattr(f->inode.get(), list, size, perms); } -int Client::removexattr(const char *path, const char *name) +int Client::removexattr(const char *path, const char *name, + const UserPerm& perms) { Mutex::Locker lock(client_lock); InodeRef in; - int r = Client::path_walk(path, &in, true); + int r = Client::path_walk(path, &in, perms, true); if (r < 0) return r; - return _removexattr(in, name); + return _removexattr(in, name, perms); } -int Client::lremovexattr(const char *path, const char *name) +int Client::lremovexattr(const char *path, const char *name, + const UserPerm& perms) { Mutex::Locker lock(client_lock); InodeRef in; - int r = Client::path_walk(path, &in, false); + int r = Client::path_walk(path, &in, perms, false); if (r < 0) return r; - return _removexattr(in, name); + return _removexattr(in, name, perms); } -int Client::fremovexattr(int fd, const char *name) +int Client::fremovexattr(int fd, const char *name, const UserPerm& perms) { Mutex::Locker lock(client_lock); Fh *f = get_filehandle(fd); if (!f) return -EBADF; - return _removexattr(f->inode, name); + return _removexattr(f->inode, name, perms); } -int Client::setxattr(const char *path, const char *name, const void *value, size_t size, int flags) +int Client::setxattr(const char *path, const char *name, const void *value, + size_t size, int flags, const UserPerm& perms) { Mutex::Locker lock(client_lock); InodeRef in; - int r = Client::path_walk(path, &in, true); + int r = Client::path_walk(path, &in, perms, true); if (r < 0) return r; - return _setxattr(in, name, value, size, flags); + return _setxattr(in, name, value, size, flags, perms); } -int Client::lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) +int Client::lsetxattr(const char *path, const char *name, const void *value, + size_t size, int flags, const UserPerm& perms) { Mutex::Locker lock(client_lock); InodeRef in; - int r = Client::path_walk(path, &in, false); + int r = Client::path_walk(path, &in, perms, false); if (r < 0) return r; - return _setxattr(in, name, value, size, flags); + return _setxattr(in, name, value, size, flags, perms); } -int Client::fsetxattr(int fd, const char *name, const void *value, size_t size, int flags) +int Client::fsetxattr(int fd, const char *name, const void *value, size_t size, + int flags, const UserPerm& perms) { Mutex::Locker lock(client_lock); Fh *f = get_filehandle(fd); if (!f) return -EBADF; - return _setxattr(f->inode, name, value, size, flags); + return _setxattr(f->inode, name, value, size, flags, perms); } int Client::_getxattr(Inode *in, const char *name, void *value, size_t size, - int uid, int gid) + const UserPerm& perms) { int r; @@ -10145,11 +10156,11 @@ int Client::_getxattr(Inode *in, const char *name, void *value, size_t size, goto out; } - r = _getattr(in, CEPH_STAT_CAP_XATTR, uid, gid, in->xattr_version == 0); + r = _getattr(in, CEPH_STAT_CAP_XATTR, perms, in->xattr_version == 0); if (r == 0) { string n(name); r = -ENODATA; - if (in->xattrs.count(n)) { + if (in->xattrs.count(n)) { r = in->xattrs[n].length(); if (r > 0 && size != 0) { if (size >= (unsigned)r) @@ -10164,18 +10175,19 @@ int Client::_getxattr(Inode *in, const char *name, void *value, size_t size, return r; } -int Client::_getxattr(InodeRef &in, const char *name, void *value, size_t size) +int Client::_getxattr(InodeRef &in, const char *name, void *value, size_t size, + const UserPerm& perms) { if (cct->_conf->client_permissions) { - int r = xattr_permission(in.get(), name, MAY_READ); + int r = xattr_permission(in.get(), name, MAY_READ, perms); if (r < 0) return r; } - return _getxattr(in.get(), name, value, size); + return _getxattr(in.get(), name, value, size, perms); } int Client::ll_getxattr(Inode *in, const char *name, void *value, - size_t size, int uid, int gid) + size_t size, const UserPerm& perms) { Mutex::Locker lock(client_lock); @@ -10187,17 +10199,18 @@ int Client::ll_getxattr(Inode *in, const char *name, void *value, tout(cct) << name << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = xattr_permission(in, name, MAY_READ, uid, gid); + int r = xattr_permission(in, name, MAY_READ, perms); if (r < 0) return r; } - return _getxattr(in, name, value, size, uid, gid); + return _getxattr(in, name, value, size, perms); } -int Client::_listxattr(Inode *in, char *name, size_t size, int uid, int gid) +int Client::_listxattr(Inode *in, char *name, size_t size, + const UserPerm& perms) { - int r = _getattr(in, CEPH_STAT_CAP_XATTR, uid, gid, in->xattr_version == 0); + int r = _getattr(in, CEPH_STAT_CAP_XATTR, perms, in->xattr_version == 0); if (r == 0) { for (map::iterator p = in->xattrs.begin(); p != in->xattrs.end(); @@ -10239,8 +10252,8 @@ int Client::_listxattr(Inode *in, char *name, size_t size, int uid, int gid) return r; } -int Client::ll_listxattr(Inode *in, char *names, size_t size, int uid, - int gid) +int Client::ll_listxattr(Inode *in, char *names, size_t size, + const UserPerm& perms) { Mutex::Locker lock(client_lock); @@ -10251,11 +10264,11 @@ int Client::ll_listxattr(Inode *in, char *names, size_t size, int uid, tout(cct) << vino.ino.val << std::endl; tout(cct) << size << std::endl; - return _listxattr(in, names, size, uid, gid); + return _listxattr(in, names, size, perms); } int Client::_do_setxattr(Inode *in, const char *name, const void *value, - size_t size, int flags, int uid, int gid) + size_t size, int flags, const UserPerm& perms) { int xattr_flags = 0; @@ -10278,7 +10291,7 @@ int Client::_do_setxattr(Inode *in, const char *name, const void *value, bl.append((const char*)value, size); req->set_data(bl); - int res = make_request(req, uid, gid); + int res = make_request(req, perms); trim_cache(); ldout(cct, 3) << "_setxattr(" << in->ino << ", \"" << name << "\") = " << @@ -10287,7 +10300,7 @@ int Client::_do_setxattr(Inode *in, const char *name, const void *value, } int Client::_setxattr(Inode *in, const char *name, const void *value, - size_t size, int flags, int uid, int gid) + size_t size, int flags, const UserPerm& perms) { if (in->snapid != CEPH_NOSNAP) { return -EROFS; @@ -10318,7 +10331,7 @@ int Client::_setxattr(Inode *in, const char *name, const void *value, if (new_mode != in->mode) { struct ceph_statx stx; stx.stx_mode = new_mode; - ret = _do_setattr(in, &stx, CEPH_SETATTR_MODE, uid, gid, NULL); + ret = _do_setattr(in, &stx, CEPH_SETATTR_MODE, perms, NULL); if (ret < 0) return ret; } @@ -10344,18 +10357,18 @@ int Client::_setxattr(Inode *in, const char *name, const void *value, return -EOPNOTSUPP; } - return _do_setxattr(in, name, value, size, flags, uid, gid); + return _do_setxattr(in, name, value, size, flags, perms); } int Client::_setxattr(InodeRef &in, const char *name, const void *value, - size_t size, int flags) + size_t size, int flags, const UserPerm& perms) { if (cct->_conf->client_permissions) { - int r = xattr_permission(in.get(), name, MAY_WRITE); + int r = xattr_permission(in.get(), name, MAY_WRITE, perms); if (r < 0) return r; } - return _setxattr(in.get(), name, value, size, flags); + return _setxattr(in.get(), name, value, size, flags, perms); } int Client::check_data_pool_exist(string name, string value, const OSDMap *osdmap) @@ -10399,7 +10412,7 @@ int Client::check_data_pool_exist(string name, string value, const OSDMap *osdma } int Client::ll_setxattr(Inode *in, const char *name, const void *value, - size_t size, int flags, int uid, int gid) + size_t size, int flags, const UserPerm& perms) { // For setting pool of layout, MetaRequest need osdmap epoch. // There is a race which create a new data pool but client and mds both don't have. @@ -10429,15 +10442,14 @@ int Client::ll_setxattr(Inode *in, const char *name, const void *value, tout(cct) << name << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = xattr_permission(in, name, MAY_WRITE, uid, gid); + int r = xattr_permission(in, name, MAY_WRITE, perms); if (r < 0) return r; } - - return _setxattr(in, name, value, size, flags, uid, gid); + return _setxattr(in, name, value, size, flags, perms); } -int Client::_removexattr(Inode *in, const char *name, int uid, int gid) +int Client::_removexattr(Inode *in, const char *name, const UserPerm& perms) { if (in->snapid != CEPH_NOSNAP) { return -EROFS; @@ -10462,24 +10474,24 @@ int Client::_removexattr(Inode *in, const char *name, int uid, int gid) req->set_filepath2(name); req->set_inode(in); - int res = make_request(req, uid, gid); + int res = make_request(req, perms); trim_cache(); ldout(cct, 3) << "_removexattr(" << in->ino << ", \"" << name << "\") = " << res << dendl; return res; } -int Client::_removexattr(InodeRef &in, const char *name) +int Client::_removexattr(InodeRef &in, const char *name, const UserPerm& perms) { if (cct->_conf->client_permissions) { - int r = xattr_permission(in.get(), name, MAY_WRITE); + int r = xattr_permission(in.get(), name, MAY_WRITE, perms); if (r < 0) return r; } - return _removexattr(in.get(), name); + return _removexattr(in.get(), name, perms); } -int Client::ll_removexattr(Inode *in, const char *name, int uid, int gid) +int Client::ll_removexattr(Inode *in, const char *name, const UserPerm& perms) { Mutex::Locker lock(client_lock); @@ -10491,12 +10503,12 @@ int Client::ll_removexattr(Inode *in, const char *name, int uid, int gid) tout(cct) << name << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = xattr_permission(in, name, MAY_WRITE, uid, gid); + int r = xattr_permission(in, name, MAY_WRITE, perms); if (r < 0) return r; } - return _removexattr(in, name, uid, gid); + return _removexattr(in, name, perms); } bool Client::_vxattrcb_quota_exists(Inode *in) @@ -10717,7 +10729,7 @@ size_t Client::_vxattrs_calcu_name_size(const VXattr *vxattr) return len; } -int Client::ll_readlink(Inode *in, char *buf, size_t buflen, int uid, int gid) +int Client::ll_readlink(Inode *in, char *buf, size_t buflen, const UserPerm& perms) { Mutex::Locker lock(client_lock); @@ -10733,17 +10745,17 @@ int Client::ll_readlink(Inode *in, char *buf, size_t buflen, int uid, int gid) ++dn; } - int r = _readlink(in, buf, buflen); + int r = _readlink(in, buf, buflen); // FIXME: no permission checking! ldout(cct, 3) << "ll_readlink " << vino << " = " << r << dendl; return r; } int Client::_mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, - int uid, int gid, InodeRef *inp) + const UserPerm& perms, InodeRef *inp) { ldout(cct, 3) << "_mknod(" << dir->ino << " " << name << ", 0" << oct - << mode << dec << ", " << rdev << ", uid " << uid << ", gid " - << gid << ")" << dendl; + << mode << dec << ", " << rdev << ", uid " << perms.uid() + << ", gid " << perms.gid() << ")" << dendl; if (strlen(name) > NAME_MAX) return -ENAMETOOLONG; @@ -10751,7 +10763,7 @@ int Client::_mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, if (dir->snapid != CEPH_NOSNAP) { return -EROFS; } - if (is_quota_files_exceeded(dir)) { + if (is_quota_files_exceeded(dir, perms)) { return -EDQUOT; } @@ -10767,7 +10779,7 @@ int Client::_mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, req->dentry_unless = CEPH_CAP_FILE_EXCL; bufferlist xattrs_bl; - int res = _posix_acl_create(dir, &mode, xattrs_bl, uid, gid); + int res = _posix_acl_create(dir, &mode, xattrs_bl, perms); if (res < 0) goto fail; req->head.args.mknod.mode = mode; @@ -10780,7 +10792,7 @@ int Client::_mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, goto fail; req->set_dentry(de); - res = make_request(req, uid, gid, inp); + res = make_request(req, perms, inp); trim_cache(); @@ -10794,7 +10806,7 @@ int Client::_mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, int Client::ll_mknod(Inode *parent, const char *name, mode_t mode, dev_t rdev, struct stat *attr, Inode **out, - int uid, int gid) + const UserPerm& perms) { Mutex::Locker lock(client_lock); @@ -10808,13 +10820,13 @@ int Client::ll_mknod(Inode *parent, const char *name, mode_t mode, tout(cct) << rdev << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = may_create(parent, uid, gid); + int r = may_create(parent, perms); if (r < 0) return r; } InodeRef in; - int r = _mknod(parent, name, mode, rdev, uid, gid, &in); + int r = _mknod(parent, name, mode, rdev, perms, &in); if (r == 0) { fill_stat(in, attr); _ll_get(in.get()); @@ -10829,7 +10841,7 @@ int Client::ll_mknod(Inode *parent, const char *name, mode_t mode, int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, InodeRef *inp, Fh **fhp, int stripe_unit, int stripe_count, int object_size, const char *data_pool, bool *created, - int uid, int gid) + const UserPerm& perms) { ldout(cct, 3) << "_create(" << dir->ino << " " << name << ", 0" << oct << mode << dec << ")" << dendl; @@ -10839,7 +10851,7 @@ int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, if (dir->snapid != CEPH_NOSNAP) { return -EROFS; } - if (is_quota_files_exceeded(dir)) { + if (is_quota_files_exceeded(dir, perms)) { return -EDQUOT; } @@ -10879,7 +10891,7 @@ int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, mode |= S_IFREG; bufferlist xattrs_bl; - int res = _posix_acl_create(dir, &mode, xattrs_bl, uid, gid); + int res = _posix_acl_create(dir, &mode, xattrs_bl, perms); if (res < 0) goto fail; req->head.args.open.mode = mode; @@ -10892,7 +10904,7 @@ int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, goto fail; req->set_dentry(de); - res = make_request(req, uid, gid, inp, created); + res = make_request(req, perms, inp, created); if (res < 0) { goto reply_error; } @@ -10900,7 +10912,7 @@ int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, /* If the caller passed a value in fhp, do the open */ if(fhp) { (*inp)->get_open_ref(cmode); - *fhp = _create_fh(inp->get(), flags, cmode); + *fhp = _create_fh(inp->get(), flags, cmode, perms); } reply_error: @@ -10919,12 +10931,12 @@ int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, } -int Client::_mkdir(Inode *dir, const char *name, mode_t mode, int uid, int gid, +int Client::_mkdir(Inode *dir, const char *name, mode_t mode, const UserPerm& perm, InodeRef *inp) { ldout(cct, 3) << "_mkdir(" << dir->ino << " " << name << ", 0" << oct - << mode << dec << ", uid " << uid << ", gid " << gid << ")" - << dendl; + << mode << dec << ", uid " << perm.uid() + << ", gid " << perm.gid() << ")" << dendl; if (strlen(name) > NAME_MAX) return -ENAMETOOLONG; @@ -10932,7 +10944,7 @@ int Client::_mkdir(Inode *dir, const char *name, mode_t mode, int uid, int gid, if (dir->snapid != CEPH_NOSNAP && dir->snapid != CEPH_SNAPDIR) { return -EROFS; } - if (is_quota_files_exceeded(dir)) { + if (is_quota_files_exceeded(dir, perm)) { return -EDQUOT; } MetaRequest *req = new MetaRequest(dir->snapid == CEPH_SNAPDIR ? @@ -10948,7 +10960,7 @@ int Client::_mkdir(Inode *dir, const char *name, mode_t mode, int uid, int gid, mode |= S_IFDIR; bufferlist xattrs_bl; - int res = _posix_acl_create(dir, &mode, xattrs_bl, uid, gid); + int res = _posix_acl_create(dir, &mode, xattrs_bl, perm); if (res < 0) goto fail; req->head.args.mkdir.mode = mode; @@ -10962,7 +10974,7 @@ int Client::_mkdir(Inode *dir, const char *name, mode_t mode, int uid, int gid, req->set_dentry(de); ldout(cct, 10) << "_mkdir: making request" << dendl; - res = make_request(req, uid, gid, inp); + res = make_request(req, perm, inp); ldout(cct, 10) << "_mkdir result is " << res << dendl; trim_cache(); @@ -10976,7 +10988,7 @@ int Client::_mkdir(Inode *dir, const char *name, mode_t mode, int uid, int gid, } int Client::ll_mkdir(Inode *parent, const char *name, mode_t mode, - struct stat *attr, Inode **out, int uid, int gid) + struct stat *attr, Inode **out, const UserPerm& perm) { Mutex::Locker lock(client_lock); @@ -10989,13 +11001,13 @@ int Client::ll_mkdir(Inode *parent, const char *name, mode_t mode, tout(cct) << mode << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = may_create(parent, uid, gid); + int r = may_create(parent, perm); if (r < 0) return r; } InodeRef in; - int r = _mkdir(parent, name, mode, uid, gid, &in); + int r = _mkdir(parent, name, mode, perm, &in); if (r == 0) { fill_stat(in, attr); _ll_get(in.get()); @@ -11007,11 +11019,12 @@ int Client::ll_mkdir(Inode *parent, const char *name, mode_t mode, return r; } -int Client::_symlink(Inode *dir, const char *name, const char *target, int uid, - int gid, InodeRef *inp) +int Client::_symlink(Inode *dir, const char *name, const char *target, + const UserPerm& perms, InodeRef *inp) { ldout(cct, 3) << "_symlink(" << dir->ino << " " << name << ", " << target - << ", uid " << uid << ", gid " << gid << ")" << dendl; + << ", uid " << perms.uid() << ", gid " << perms.gid() << ")" + << dendl; if (strlen(name) > NAME_MAX) return -ENAMETOOLONG; @@ -11019,7 +11032,7 @@ int Client::_symlink(Inode *dir, const char *name, const char *target, int uid, if (dir->snapid != CEPH_NOSNAP) { return -EROFS; } - if (is_quota_files_exceeded(dir)) { + if (is_quota_files_exceeded(dir, perms)) { return -EDQUOT; } @@ -11040,7 +11053,7 @@ int Client::_symlink(Inode *dir, const char *name, const char *target, int uid, goto fail; req->set_dentry(de); - res = make_request(req, uid, gid, inp); + res = make_request(req, perms, inp); trim_cache(); ldout(cct, 3) << "_symlink(\"" << path << "\", \"" << target << "\") = " << @@ -11053,7 +11066,7 @@ int Client::_symlink(Inode *dir, const char *name, const char *target, int uid, } int Client::ll_symlink(Inode *parent, const char *name, const char *value, - struct stat *attr, Inode **out, int uid, int gid) + struct stat *attr, Inode **out, const UserPerm& perms) { Mutex::Locker lock(client_lock); @@ -11067,13 +11080,13 @@ int Client::ll_symlink(Inode *parent, const char *name, const char *value, tout(cct) << value << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = may_create(parent, uid, gid); + int r = may_create(parent, perms); if (r < 0) return r; } InodeRef in; - int r = _symlink(parent, name, value, uid, gid, &in); + int r = _symlink(parent, name, value, perms, &in); if (r == 0) { fill_stat(in, attr); _ll_get(in.get()); @@ -11085,9 +11098,11 @@ int Client::ll_symlink(Inode *parent, const char *name, const char *value, return r; } -int Client::_unlink(Inode *dir, const char *name, int uid, int gid) +int Client::_unlink(Inode *dir, const char *name, const UserPerm& perm) { - ldout(cct, 3) << "_unlink(" << dir->ino << " " << name << " uid " << uid << " gid " << gid << ")" << dendl; + ldout(cct, 3) << "_unlink(" << dir->ino << " " << name + << " uid " << perm.uid() << " gid " << perm.gid() + << ")" << dendl; if (dir->snapid != CEPH_NOSNAP) { return -EROFS; @@ -11110,7 +11125,7 @@ int Client::_unlink(Inode *dir, const char *name, int uid, int gid) req->dentry_drop = CEPH_CAP_FILE_SHARED; req->dentry_unless = CEPH_CAP_FILE_EXCL; - res = _lookup(dir, name, 0, &otherin, uid, gid); + res = _lookup(dir, name, 0, &otherin, perm); if (res < 0) goto fail; req->set_other_inode(otherin.get()); @@ -11118,7 +11133,7 @@ int Client::_unlink(Inode *dir, const char *name, int uid, int gid) req->set_inode(dir); - res = make_request(req, uid, gid); + res = make_request(req, perm); trim_cache(); ldout(cct, 3) << "unlink(" << path << ") = " << res << dendl; @@ -11129,7 +11144,7 @@ int Client::_unlink(Inode *dir, const char *name, int uid, int gid) return res; } -int Client::ll_unlink(Inode *in, const char *name, int uid, int gid) +int Client::ll_unlink(Inode *in, const char *name, const UserPerm& perm) { Mutex::Locker lock(client_lock); @@ -11141,17 +11156,17 @@ int Client::ll_unlink(Inode *in, const char *name, int uid, int gid) tout(cct) << name << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = may_delete(in, name, uid, gid); + int r = may_delete(in, name, perm); if (r < 0) return r; } - return _unlink(in, name, uid, gid); + return _unlink(in, name, perm); } -int Client::_rmdir(Inode *dir, const char *name, int uid, int gid) +int Client::_rmdir(Inode *dir, const char *name, const UserPerm& perms) { - ldout(cct, 3) << "_rmdir(" << dir->ino << " " << name << " uid " << uid << - " gid " << gid << ")" << dendl; + ldout(cct, 3) << "_rmdir(" << dir->ino << " " << name << " uid " + << perms.uid() << " gid " << perms.gid() << ")" << dendl; if (dir->snapid != CEPH_NOSNAP && dir->snapid != CEPH_SNAPDIR) { return -EROFS; @@ -11173,7 +11188,7 @@ int Client::_rmdir(Inode *dir, const char *name, int uid, int gid) int res = get_or_create(dir, name, &de); if (res < 0) goto fail; - res = _lookup(dir, name, 0, &in, uid, gid); + res = _lookup(dir, name, 0, &in, perms); if (res < 0) goto fail; if (req->get_op() == CEPH_MDS_OP_RMDIR) { @@ -11185,7 +11200,7 @@ int Client::_rmdir(Inode *dir, const char *name, int uid, int gid) req->set_other_inode(in.get()); } - res = make_request(req, uid, gid); + res = make_request(req, perms); trim_cache(); ldout(cct, 3) << "rmdir(" << path << ") = " << res << dendl; @@ -11196,7 +11211,7 @@ int Client::_rmdir(Inode *dir, const char *name, int uid, int gid) return res; } -int Client::ll_rmdir(Inode *in, const char *name, int uid, int gid) +int Client::ll_rmdir(Inode *in, const char *name, const UserPerm& perms) { Mutex::Locker lock(client_lock); @@ -11208,18 +11223,20 @@ int Client::ll_rmdir(Inode *in, const char *name, int uid, int gid) tout(cct) << name << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = may_delete(in, name, uid, gid); + int r = may_delete(in, name, perms); if (r < 0) return r; } - return _rmdir(in, name, uid, gid); + return _rmdir(in, name, perms); } -int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const char *toname, int uid, int gid) +int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const char *toname, const UserPerm& perm) { - ldout(cct, 3) << "_rename(" << fromdir->ino << " " << fromname << " to " << todir->ino << " " << toname - << " uid " << uid << " gid " << gid << ")" << dendl; + ldout(cct, 3) << "_rename(" << fromdir->ino << " " << fromname << " to " + << todir->ino << " " << toname + << " uid " << perm.uid() << " gid " << perm.gid() << ")" + << dendl; if (fromdir->snapid != todir->snapid) return -EXDEV; @@ -11235,7 +11252,7 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch fromdir != todir && (fromdir->quota.is_enable() || todir->quota.is_enable() || - get_quota_root(fromdir) != get_quota_root(todir))) { + get_quota_root(fromdir, perm) != get_quota_root(todir, perm))) { return -EXDEV; } @@ -11270,13 +11287,13 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch req->dentry_unless = CEPH_CAP_FILE_EXCL; InodeRef oldin, otherin; - res = _lookup(fromdir, fromname, 0, &oldin, uid, gid); + res = _lookup(fromdir, fromname, 0, &oldin, perm); if (res < 0) goto fail; req->set_old_inode(oldin.get()); req->old_inode_drop = CEPH_CAP_LINK_SHARED; - res = _lookup(todir, toname, 0, &otherin, uid, gid); + res = _lookup(todir, toname, 0, &otherin, perm); if (res != 0 && res != -ENOENT) { goto fail; } else if (res == 0) { @@ -11292,7 +11309,7 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch unlink(de, true, true); } - res = make_request(req, uid, gid, &target); + res = make_request(req, perm, &target); ldout(cct, 10) << "rename result is " << res << dendl; // renamed item from our cache @@ -11307,7 +11324,7 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch } int Client::ll_rename(Inode *parent, const char *name, Inode *newparent, - const char *newname, int uid, int gid) + const char *newname, const UserPerm& perm) { Mutex::Locker lock(client_lock); @@ -11323,21 +11340,21 @@ int Client::ll_rename(Inode *parent, const char *name, Inode *newparent, tout(cct) << newname << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = may_delete(parent, name, uid, gid); + int r = may_delete(parent, name, perm); if (r < 0) return r; - r = may_delete(newparent, newname, uid, gid); + r = may_delete(newparent, newname, perm); if (r < 0 && r != -ENOENT) return r; } - return _rename(parent, name, newparent, newname, uid, gid); + return _rename(parent, name, newparent, newname, perm); } -int Client::_link(Inode *in, Inode *dir, const char *newname, int uid, int gid, InodeRef *inp) +int Client::_link(Inode *in, Inode *dir, const char *newname, const UserPerm& perm, InodeRef *inp) { ldout(cct, 3) << "_link(" << in->ino << " to " << dir->ino << " " << newname - << " uid " << uid << " gid " << gid << ")" << dendl; + << " uid " << perm.uid() << " gid " << perm.gid() << ")" << dendl; if (strlen(newname) > NAME_MAX) return -ENAMETOOLONG; @@ -11345,7 +11362,7 @@ int Client::_link(Inode *in, Inode *dir, const char *newname, int uid, int gid, if (in->snapid != CEPH_NOSNAP || dir->snapid != CEPH_NOSNAP) { return -EROFS; } - if (is_quota_files_exceeded(dir)) { + if (is_quota_files_exceeded(dir, perm)) { return -EDQUOT; } @@ -11366,7 +11383,7 @@ int Client::_link(Inode *in, Inode *dir, const char *newname, int uid, int gid, goto fail; req->set_dentry(de); - res = make_request(req, uid, gid, inp); + res = make_request(req, perm, inp); ldout(cct, 10) << "link result is " << res << dendl; trim_cache(); @@ -11379,7 +11396,7 @@ int Client::_link(Inode *in, Inode *dir, const char *newname, int uid, int gid, } int Client::ll_link(Inode *in, Inode *newparent, const char *newname, - struct stat *attr, int uid, int gid) + struct stat *attr, const UserPerm& perm) { Mutex::Locker lock(client_lock); @@ -11401,15 +11418,15 @@ int Client::ll_link(Inode *in, Inode *newparent, const char *newname, r = -EPERM; goto out; } - r = may_hardlink(in, uid, gid); + r = may_hardlink(in, perm); if (r < 0) goto out; - r = may_create(newparent, uid, gid); + r = may_create(newparent, perm); if (r < 0) goto out; } - r = _link(in, newparent, newname, uid, gid, &target); + r = _link(in, newparent, newname, perm, &target); if (r == 0) { assert(target); fill_stat(target, attr); @@ -11513,7 +11530,7 @@ uint64_t Client::ll_get_internal_offset(Inode *in, uint64_t blockno) } int Client::ll_opendir(Inode *in, int flags, dir_result_t** dirpp, - int uid, int gid) + const UserPerm& perms) { Mutex::Locker lock(client_lock); @@ -11524,12 +11541,12 @@ int Client::ll_opendir(Inode *in, int flags, dir_result_t** dirpp, tout(cct) << vino.ino.val << std::endl; if (!cct->_conf->fuse_default_permissions) { - int r = may_open(in, flags, uid, gid); + int r = may_open(in, flags, perms); if (r < 0) return r; } - int r = _opendir(in, dirpp, uid, gid); + int r = _opendir(in, dirpp, perms); tout(cct) << (unsigned long)*dirpp << std::endl; ldout(cct, 3) << "ll_opendir " << vino << " = " << r << " (" << *dirpp << ")" @@ -11557,7 +11574,7 @@ int Client::ll_fsyncdir(dir_result_t *dirp) return _fsync(dirp->inode.get(), false); } -int Client::ll_open(Inode *in, int flags, Fh **fhp, int uid, int gid) +int Client::ll_open(Inode *in, int flags, Fh **fhp, const UserPerm& perms) { assert(!(flags & O_CREAT)); @@ -11571,17 +11588,13 @@ int Client::ll_open(Inode *in, int flags, Fh **fhp, int uid, int gid) tout(cct) << flags << std::endl; int r; - if (uid < 0) { - uid = get_uid(); - gid = get_gid(); - } if (!cct->_conf->fuse_default_permissions) { - r = may_open(in, flags, uid, gid); + r = may_open(in, flags, perms); if (r < 0) goto out; } - r = _open(in, flags, 0, fhp /* may be NULL */, uid, gid); + r = _open(in, flags, 0, fhp /* may be NULL */, perms); out: Fh *fhptr = fhp ? *fhp : NULL; @@ -11596,7 +11609,7 @@ int Client::ll_open(Inode *in, int flags, Fh **fhp, int uid, int gid) int Client::ll_create(Inode *parent, const char *name, mode_t mode, int flags, struct stat *attr, Inode **outp, Fh **fhp, - int uid, int gid) + const UserPerm& perms) { *fhp = NULL; @@ -11605,7 +11618,8 @@ int Client::ll_create(Inode *parent, const char *name, mode_t mode, vinodeno_t vparent = _get_vino(parent); ldout(cct, 3) << "ll_create " << vparent << " " << name << " 0" << oct << - mode << dec << " " << flags << ", uid " << uid << ", gid " << gid << dendl; + mode << dec << " " << flags << ", uid " << perms.uid() + << ", gid " << perms.gid() << dendl; tout(cct) << "ll_create" << std::endl; tout(cct) << vparent.ino.val << std::endl; tout(cct) << name << std::endl; @@ -11614,19 +11628,19 @@ int Client::ll_create(Inode *parent, const char *name, mode_t mode, bool created = false; InodeRef in; - int r = _lookup(parent, name, CEPH_STAT_CAP_INODE_ALL, &in, uid, gid); + int r = _lookup(parent, name, CEPH_STAT_CAP_INODE_ALL, &in, perms); if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL)) return -EEXIST; if (r == -ENOENT && (flags & O_CREAT)) { if (!cct->_conf->fuse_default_permissions) { - r = may_create(parent, uid, gid); + r = may_create(parent, perms); if (r < 0) goto out; } r = _create(parent, name, flags, mode, &in, fhp, 0, 0, 0, NULL, &created, - uid, gid); + perms); if (r < 0) goto out; } @@ -11640,7 +11654,7 @@ int Client::ll_create(Inode *parent, const char *name, mode_t mode, ldout(cct, 20) << "ll_create created = " << created << dendl; if (!created) { if (!cct->_conf->fuse_default_permissions) { - r = may_open(in.get(), flags, uid, gid); + r = may_open(in.get(), flags, perms); if (r < 0) { if (*fhp) { int release_r = _release_fh(*fhp); @@ -11650,7 +11664,7 @@ int Client::ll_create(Inode *parent, const char *name, mode_t mode, } } if (*fhp == NULL) { - r = _open(in.get(), flags, mode, fhp, uid, gid); + r = _open(in.get(), flags, mode, fhp, perms); if (r < 0) goto out; } @@ -11679,14 +11693,15 @@ int Client::ll_create(Inode *parent, const char *name, mode_t mode, return r; } -loff_t Client::ll_lseek(Fh *fh, loff_t offset, int whence) +loff_t Client::ll_lseek(Fh *fh, loff_t offset, int whence, + const UserPerm& perms) { Mutex::Locker lock(client_lock); tout(cct) << "ll_lseek" << std::endl; tout(cct) << offset << std::endl; tout(cct) << whence << std::endl; - return _lseek(fh, offset, whence); + return _lseek(fh, offset, whence, perms); } int Client::ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl) @@ -11901,7 +11916,7 @@ int Client::_fallocate(Fh *fh, int mode, int64_t offset, int64_t length) uint64_t size = offset + length; if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)) && size > in->size && - is_quota_bytes_exceeded(in, size - in->size)) { + is_quota_bytes_exceeded(in, size - in->size, fh->actor_perms)) { return -EDQUOT; } @@ -11981,7 +11996,7 @@ int Client::_fallocate(Fh *fh, int mode, int64_t offset, int64_t length) in->change_attr++; mark_caps_dirty(in, CEPH_CAP_FILE_WR); - if (is_quota_bytes_approaching(in)) { + if (is_quota_bytes_approaching(in, fh->actor_perms)) { check_caps(in, true); } else { if ((in->size << 1) >= in->max_size && @@ -12118,13 +12133,14 @@ void Client::ll_interrupt(void *d) // expose file layouts -int Client::describe_layout(const char *relpath, file_layout_t *lp) +int Client::describe_layout(const char *relpath, file_layout_t *lp, + const UserPerm& perms) { Mutex::Locker lock(client_lock); filepath path(relpath); InodeRef in; - int r = path_walk(path, &in); + int r = path_walk(path, &in, perms); if (r < 0) return r; @@ -12388,7 +12404,7 @@ bool Client::ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool return true; } -Inode *Client::get_quota_root(Inode *in) +Inode *Client::get_quota_root(Inode *in, const UserPerm& perms) { if (!cct->_conf->client_quota) return NULL; @@ -12436,7 +12452,7 @@ Inode *Client::get_quota_root(Inode *in) req->set_inode(cur); InodeRef parent_ref; - int ret = make_request(req, -1, -1, &parent_ref); + int ret = make_request(req, perms, &parent_ref); if (ret < 0) { ldout(cct, 1) << __func__ << " " << in->vino() << " failed to find parent of " << cur->vino() @@ -12461,8 +12477,8 @@ Inode *Client::get_quota_root(Inode *in) * Traverse quota ancestors of the Inode, return true * if any of them passes the passed function */ -bool Client::check_quota_condition( - Inode *in, std::function test) +bool Client::check_quota_condition(Inode *in, const UserPerm& perms, + std::function test) { if (!cct->_conf->client_quota) return false; @@ -12478,33 +12494,34 @@ bool Client::check_quota_condition( return false; } else { // Continue up the tree - in = get_quota_root(in); + in = get_quota_root(in, perms); } } return false; } -bool Client::is_quota_files_exceeded(Inode *in) +bool Client::is_quota_files_exceeded(Inode *in, const UserPerm& perms) { - return check_quota_condition(in, + return check_quota_condition(in, perms, [](const Inode &in) { return in.quota.max_files && in.rstat.rsize() >= in.quota.max_files; }); } -bool Client::is_quota_bytes_exceeded(Inode *in, int64_t new_bytes) +bool Client::is_quota_bytes_exceeded(Inode *in, int64_t new_bytes, + const UserPerm& perms) { - return check_quota_condition(in, + return check_quota_condition(in, perms, [&new_bytes](const Inode &in) { return in.quota.max_bytes && (in.rstat.rbytes + new_bytes) > in.quota.max_bytes; }); } -bool Client::is_quota_bytes_approaching(Inode *in) +bool Client::is_quota_bytes_approaching(Inode *in, const UserPerm& perms) { - return check_quota_condition(in, + return check_quota_condition(in, perms, [](const Inode &in) { if (in.quota.max_bytes) { if (in.rstat.rbytes >= in.quota.max_bytes) { @@ -12631,23 +12648,24 @@ int Client::check_pool_perm(Inode *in, int need) return 0; } -int Client::_posix_acl_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want) +int Client::_posix_acl_permission(Inode *in, const UserPerm& perms, unsigned want) { if (acl_type == POSIX_ACL) { if (in->xattrs.count(ACL_EA_ACCESS)) { const bufferptr& access_acl = in->xattrs[ACL_EA_ACCESS]; - return posix_acl_permits(access_acl, in->uid, in->gid, uid, groups, want); + + return posix_acl_permits(access_acl, in->uid, in->gid, perms, want); } } return -EAGAIN; } -int Client::_posix_acl_chmod(Inode *in, mode_t mode, int uid, int gid) +int Client::_posix_acl_chmod(Inode *in, mode_t mode, const UserPerm& perms) { if (acl_type == NO_ACL) return 0; - int r = _getattr(in, CEPH_STAT_CAP_XATTR, uid, gid, in->xattr_version == 0); + int r = _getattr(in, CEPH_STAT_CAP_XATTR, perms, in->xattr_version == 0); if (r < 0) goto out; @@ -12658,7 +12676,7 @@ int Client::_posix_acl_chmod(Inode *in, mode_t mode, int uid, int gid) r = posix_acl_access_chmod(acl, mode); if (r < 0) goto out; - r = _do_setxattr(in, ACL_EA_ACCESS, acl.c_str(), acl.length(), 0, uid, gid); + r = _do_setxattr(in, ACL_EA_ACCESS, acl.c_str(), acl.length(), 0, perms); } else { r = 0; } @@ -12669,7 +12687,7 @@ int Client::_posix_acl_chmod(Inode *in, mode_t mode, int uid, int gid) } int Client::_posix_acl_create(Inode *dir, mode_t *mode, bufferlist& xattrs_bl, - int uid, int gid) + const UserPerm& perms) { if (acl_type == NO_ACL) return 0; @@ -12677,7 +12695,7 @@ int Client::_posix_acl_create(Inode *dir, mode_t *mode, bufferlist& xattrs_bl, if (S_ISLNK(*mode)) return 0; - int r = _getattr(dir, CEPH_STAT_CAP_XATTR, uid, gid, dir->xattr_version == 0); + int r = _getattr(dir, CEPH_STAT_CAP_XATTR, perms, dir->xattr_version == 0); if (r < 0) goto out; @@ -12772,30 +12790,11 @@ void Client::handle_conf_change(const struct md_config_t *conf, } } -bool Client::RequestUserGroups::is_in(gid_t id) +void Client::init_groups(UserPerm *perms) { - if (id == gid) - return true; - if (sgid_count < 0) - init(); - for (int i = 0; i < sgid_count; ++i) { - if (id == sgids[i]) - return true; - } - return false; -} - -int Client::RequestUserGroups::get_gids(const gid_t **out) -{ - if (sgid_count < 0) - init(); - if (sgid_count > 0) { - *out = sgids; - return sgid_count; - } else { - *out = &gid; - return 1; - } + gid_t *sgids; + int count = _getgrouplist(&sgids, perms->uid(), perms->gid()); + perms->init_gids(sgids, count); } void intrusive_ptr_add_ref(Inode *in) diff --git a/src/client/Client.h b/src/client/Client.h index 9c1bf4dfdd082..75a35d21e0f4d 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -46,7 +46,7 @@ using std::fstream; #include "osdc/ObjectCacher.h" #include "InodeRef.h" -#include "UserGroups.h" +#include "UserPerm.h" class FSMap; class FSMapUser; @@ -185,9 +185,6 @@ struct dir_result_t { } InodeRef inode; - int owner_uid; - int owner_gid; - int64_t offset; // hash order: // (0xff << 52) | ((24 bits hash) << 28) | // (the nth entry has hash collision); @@ -201,6 +198,7 @@ struct dir_result_t { uint64_t ordered_count; unsigned cache_index; int start_shared_gen; // dir shared_gen at start of readdir + UserPerm perms; frag_t buffer_frag; @@ -219,7 +217,7 @@ struct dir_result_t { }; vector buffer; - explicit dir_result_t(Inode *in); + explicit dir_result_t(Inode *in, const UserPerm& perms); unsigned offset_high() { return fpos_high(offset); } unsigned offset_low() { return fpos_low(offset); } @@ -294,6 +292,17 @@ class Client : public Dispatcher, public md_config_obs_t { public: void tick(); + UserPerm pick_my_perms() { + uid_t uid = user_id >= 0 ? user_id : ::geteuid(); + gid_t gid = group_id >= 0 ? group_id : ::getegid(); + return UserPerm(uid, gid); + } + + static UserPerm pick_my_perms(CephContext *c) { + uid_t uid = c->_conf->client_mount_uid >= 0 ? c->_conf->client_mount_uid : ::geteuid(); + gid_t gid = c->_conf->client_mount_gid >= 0 ? c->_conf->client_mount_gid : ::getegid(); + return UserPerm(uid, gid); + } protected: MonClient *monclient; Messenger *messenger; @@ -302,17 +311,6 @@ class Client : public Dispatcher, public md_config_obs_t { int user_id, group_id; int acl_type; - int get_uid() { - if (user_id >= 0) - return user_id; - return ::geteuid(); - } - int get_gid() { - if (group_id >= 0) - return group_id; - return ::getegid(); - } - void set_cap_epoch_barrier(epoch_t e); epoch_t cap_epoch_barrier; @@ -358,15 +356,15 @@ class Client : public Dispatcher, public md_config_obs_t { void dump_mds_requests(Formatter *f); void dump_mds_sessions(Formatter *f); - int make_request(MetaRequest *req, int uid, int gid, - //MClientRequest *req, int uid, int gid, + int make_request(MetaRequest *req, const UserPerm& perms, InodeRef *ptarget = 0, bool *pcreated = 0, int use_mds=-1, bufferlist *pdirbl=0); void put_request(MetaRequest *request); void unregister_request(MetaRequest *request); int verify_reply_trace(int r, MetaRequest *request, MClientReply *reply, - InodeRef *ptarget, bool *pcreated, int uid, int gid); + InodeRef *ptarget, bool *pcreated, + const UserPerm& perms); void encode_cap_releases(MetaRequest *request, mds_rank_t mds); int encode_inode_release(Inode *in, MetaRequest *req, mds_rank_t mds, int drop, @@ -518,8 +516,9 @@ class Client : public Dispatcher, public md_config_obs_t { // path traversal for high-level interface InodeRef cwd; - int path_walk(const filepath& fp, InodeRef *end, bool followsym=true, - int mask=0, int uid=-1, int gid=-1); + int path_walk(const filepath& fp, InodeRef *end, const UserPerm& perms, + bool followsym=true, int mask=0, int uid=-1, int gid=-1); + int fill_stat(Inode *in, struct stat *st, frag_info_t *dirstat=0, nest_info_t *rstat=0); int fill_stat(InodeRef& in, struct stat *st, frag_info_t *dirstat=0, nest_info_t *rstat=0) { return fill_stat(in.get(), st, dirstat, rstat); @@ -566,13 +565,13 @@ class Client : public Dispatcher, public md_config_obs_t { int authenticate(); - Inode* get_quota_root(Inode *in); - bool check_quota_condition( - Inode *in, - std::function test); - bool is_quota_files_exceeded(Inode *in); - bool is_quota_bytes_exceeded(Inode *in, int64_t new_bytes); - bool is_quota_bytes_approaching(Inode *in); + Inode* get_quota_root(Inode *in, const UserPerm& perms); + bool check_quota_condition(Inode *in, const UserPerm& perms, + std::function test); + bool is_quota_files_exceeded(Inode *in, const UserPerm& perms); + bool is_quota_bytes_exceeded(Inode *in, int64_t new_bytes, + const UserPerm& perms); + bool is_quota_bytes_approaching(Inode *in, const UserPerm& perms); std::map, int> pool_perms; list waiting_for_pool_perm; @@ -621,7 +620,7 @@ class Client : public Dispatcher, public md_config_obs_t { void check_cap_issue(Inode *in, Cap *cap, unsigned issued); void add_update_cap(Inode *in, MetaSession *session, uint64_t cap_id, unsigned issued, unsigned seq, unsigned mseq, inodeno_t realm, - int flags); + int flags, const UserPerm& perms); void remove_cap(Cap *cap, bool queue_release); void remove_all_caps(Inode *in); void remove_session_caps(MetaSession *session); @@ -704,7 +703,8 @@ class Client : public Dispatcher, public md_config_obs_t { uint64_t change_attr, uint64_t time_warp_seq, utime_t ctime, utime_t mtime, utime_t atime, version_t inline_version, bufferlist& inline_data, int issued); - Inode *add_update_inode(InodeStat *st, utime_t ttl, MetaSession *session); + Inode *add_update_inode(InodeStat *st, utime_t ttl, MetaSession *session, + const UserPerm& request_perms); Dentry *insert_dentry_inode(Dir *dir, const string& dname, LeaseStat *dlease, Inode *in, utime_t from, MetaSession *session, Dentry *old_dentry = NULL); @@ -722,7 +722,7 @@ class Client : public Dispatcher, public md_config_obs_t { // some readdir helpers typedef int (*add_dirent_cb_t)(void *p, struct dirent *de, struct stat *st, int stmask, off_t off); - int _opendir(Inode *in, dir_result_t **dirpp, int uid=-1, int gid=-1); + int _opendir(Inode *in, dir_result_t **dirpp, const UserPerm& perms); void _readdir_drop_dirp_buffer(dir_result_t *dirp); bool _readdir_have_frag(dir_result_t *dirp); void _readdir_next_frag(dir_result_t *dirp); @@ -738,7 +738,7 @@ class Client : public Dispatcher, public md_config_obs_t { int _ll_put(Inode *in, int num); void _ll_drop_pins(); - Fh *_create_fh(Inode *in, int flags, int cmode); + Fh *_create_fh(Inode *in, int flags, int cmode, const UserPerm& perms); int _release_fh(Fh *fh); void _put_fh(Fh *fh); @@ -756,43 +756,61 @@ class Client : public Dispatcher, public md_config_obs_t { // internal interface // call these with client_lock held! - int _do_lookup(Inode *dir, const string& name, int mask, InodeRef *target, int uid, int gid); - int _lookup(Inode *dir, const string& dname, int mask, InodeRef *target, int uid, int gid); - - int _link(Inode *in, Inode *dir, const char *name, int uid=-1, int gid=-1, InodeRef *inp = 0); - int _unlink(Inode *dir, const char *name, int uid=-1, int gid=-1); - int _rename(Inode *olddir, const char *oname, Inode *ndir, const char *nname, int uid=-1, int gid=-1); - int _mkdir(Inode *dir, const char *name, mode_t mode, int uid=-1, int gid=-1, InodeRef *inp = 0); - int _rmdir(Inode *dir, const char *name, int uid=-1, int gid=-1); - int _symlink(Inode *dir, const char *name, const char *target, int uid=-1, int gid=-1, InodeRef *inp = 0); - int _mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, int uid=-1, int gid=-1, InodeRef *inp = 0); - int _do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid, InodeRef *inp); + int _do_lookup(Inode *dir, const string& name, int mask, InodeRef *target, + const UserPerm& perms); + + int _lookup(Inode *dir, const string& dname, int mask, InodeRef *target, + const UserPerm& perm); + + int _link(Inode *in, Inode *dir, const char *name, const UserPerm& perm, + InodeRef *inp = 0); + int _unlink(Inode *dir, const char *name, const UserPerm& perm); + int _rename(Inode *olddir, const char *oname, Inode *ndir, const char *nname, const UserPerm& perm); + int _mkdir(Inode *dir, const char *name, mode_t mode, const UserPerm& perm, + InodeRef *inp = 0); + int _rmdir(Inode *dir, const char *name, const UserPerm& perms); + int _symlink(Inode *dir, const char *name, const char *target, + const UserPerm& perms, InodeRef *inp = 0); + int _mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, + const UserPerm& perms, InodeRef *inp = 0); + int _do_setattr(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms, InodeRef *inp); void stat_to_statx(struct stat *st, struct ceph_statx *stx); - int __setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid=-1, int gid=-1, InodeRef *inp = 0); - int _setattrx(InodeRef &in, struct ceph_statx *stx, int mask); - int _setattr(InodeRef &in, struct stat *attr, int mask); - int _ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid = -1, - int gid = -1, InodeRef *inp = 0); - int _getattr(Inode *in, int mask, int uid=-1, int gid=-1, bool force=false); - int _getattr(InodeRef &in, int mask, int uid=-1, int gid=-1, bool force=false) { - return _getattr(in.get(), mask, uid, gid, force); + int __setattrx(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms, InodeRef *inp = 0); + int _setattrx(InodeRef &in, struct ceph_statx *stx, int mask, + const UserPerm& perms); + int _setattr(InodeRef &in, struct stat *attr, int mask, + const UserPerm& perms); + int _ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms, InodeRef *inp = 0); + int _getattr(Inode *in, int mask, const UserPerm& perms, bool force=false); + int _getattr(InodeRef &in, int mask, const UserPerm& perms, bool force=false) { + return _getattr(in.get(), mask, perms, force); } int _readlink(Inode *in, char *buf, size_t size); - int _getxattr(Inode *in, const char *name, void *value, size_t len, int uid=-1, int gid=-1); - int _getxattr(InodeRef &in, const char *name, void *value, size_t len); - int _listxattr(Inode *in, char *names, size_t len, int uid=-1, int gid=-1); - int _do_setxattr(Inode *in, const char *name, const void *value, size_t len, int flags, int uid, int gid); - int _setxattr(Inode *in, const char *name, const void *value, size_t len, int flags, int uid=-1, int gid=-1); - int _setxattr(InodeRef &in, const char *name, const void *value, size_t len, int flags); - int _removexattr(Inode *in, const char *nm, int uid=-1, int gid=-1); - int _removexattr(InodeRef &in, const char *nm); - int _open(Inode *in, int flags, mode_t mode, Fh **fhp, int uid, int gid); + int _getxattr(Inode *in, const char *name, void *value, size_t len, + const UserPerm& perms); + int _getxattr(InodeRef &in, const char *name, void *value, size_t len, + const UserPerm& perms); + int _listxattr(Inode *in, char *names, size_t len, const UserPerm& perms); + int _do_setxattr(Inode *in, const char *name, const void *value, size_t len, + int flags, const UserPerm& perms); + int _setxattr(Inode *in, const char *name, const void *value, size_t len, + int flags, const UserPerm& perms); + int _setxattr(InodeRef &in, const char *name, const void *value, size_t len, + int flags, const UserPerm& perms); + int _removexattr(Inode *in, const char *nm, const UserPerm& perms); + int _removexattr(InodeRef &in, const char *nm, const UserPerm& perms); + int _open(Inode *in, int flags, mode_t mode, Fh **fhp, + const UserPerm& perms); int _renew_caps(Inode *in); - int _create(Inode *in, const char *name, int flags, mode_t mode, InodeRef *inp, Fh **fhp, - int stripe_unit, int stripe_count, int object_size, const char *data_pool, - bool *created, int uid, int gid); + int _create(Inode *in, const char *name, int flags, mode_t mode, InodeRef *inp, + Fh **fhp, int stripe_unit, int stripe_count, int object_size, + const char *data_pool, bool *created, const UserPerm &perms); loff_t _lseek(Fh *fh, loff_t offset, int whence); + loff_t _lseek(Fh *fh, loff_t offset, int whence, const UserPerm& perms); int _read(Fh *fh, int64_t offset, uint64_t size, bufferlist *bl); int _write(Fh *fh, int64_t offset, uint64_t size, const char *buf, const struct iovec *iov, int iovcnt); @@ -820,36 +838,21 @@ class Client : public Dispatcher, public md_config_obs_t { MAY_READ = 4, }; - class RequestUserGroups : public UserGroups { - Client *client; - uid_t uid; - gid_t gid; - int sgid_count; - gid_t *sgids; - void init() { - sgid_count = client->_getgrouplist(&sgids, uid, gid); - } - public: - RequestUserGroups(Client *c, uid_t u, gid_t g) : - client(c), uid(u), gid(g), sgid_count(-1), sgids(NULL) {} - ~RequestUserGroups() { - free(sgids); - } - gid_t get_gid() { return gid; } - bool is_in(gid_t id); - int get_gids(const gid_t **out); - }; + void init_groups(UserPerm *groups); + + int inode_permission(Inode *in, const UserPerm& perms, unsigned want); + int xattr_permission(Inode *in, const char *name, unsigned want, + const UserPerm& perms); + int may_setattr(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms); + int may_open(Inode *in, int flags, const UserPerm& perms); + int may_lookup(Inode *dir, const UserPerm& perms); + int may_create(Inode *dir, const UserPerm& perms); + int may_delete(Inode *dir, const char *name, const UserPerm& perms); + int may_hardlink(Inode *in, const UserPerm& perms); - int inode_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want); - int xattr_permission(Inode *in, const char *name, unsigned want, int uid=-1, int gid=-1); - int may_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid=-1, int gid=-1); - int may_open(Inode *in, int flags, int uid=-1, int gid=-1); - int may_lookup(Inode *dir, 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 may_hardlink(Inode *in, int uid=-1, int gid=-1); - int _getattr_for_perm(Inode *in, int uid, int gid); - int _getgrouplist(gid_t **sgids, int uid, int gid); + int _getattr_for_perm(Inode *in, const UserPerm& perms); + int _getgrouplist(gid_t **sgids, uid_t uid, gid_t gid); int check_data_pool_exist(string name, string value, const OSDMap *osdmap); @@ -906,22 +909,24 @@ class Client : public Dispatcher, public md_config_obs_t { } int _do_filelock(Inode *in, Fh *fh, int lock_type, int op, int sleep, - struct flock *fl, uint64_t owner); + struct flock *fl, uint64_t owner, bool removing=false); int _interrupt_filelock(MetaRequest *req); void _encode_filelocks(Inode *in, bufferlist& bl); void _release_filelocks(Fh *fh); void _update_lock_state(struct flock *fl, uint64_t owner, ceph_lock_state_t *lock_state); - int _posix_acl_create(Inode *dir, mode_t *mode, bufferlist& xattrs_bl, int uid, int gid); - int _posix_acl_chmod(Inode *in, mode_t mode, int uid, int gid); - int _posix_acl_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want); + int _posix_acl_create(Inode *dir, mode_t *mode, bufferlist& xattrs_bl, + const UserPerm& perms); + int _posix_acl_chmod(Inode *in, mode_t mode, const UserPerm& perms); + int _posix_acl_permission(Inode *in, const UserPerm& perms, unsigned want); mds_rank_t _get_random_up_mds() const; - int _ll_getattr(Inode *in, int uid, int gid); + int _ll_getattr(Inode *in, const UserPerm& perms); public: - int mount(const std::string &mount_root, bool require_mds=false); + int mount(const std::string &mount_root, const UserPerm& perms, + bool require_mds=false); void unmount(); int mds_command( @@ -931,14 +936,14 @@ class Client : public Dispatcher, public md_config_obs_t { bufferlist *poutbl, std::string *prs, Context *onfinish); // these shoud (more or less) mirror the actual system calls. - int statfs(const char *path, struct statvfs *stbuf); + int statfs(const char *path, struct statvfs *stbuf, const UserPerm& perms); // crap - int chdir(const char *s, std::string &new_cwd); - void getcwd(std::string& cwd); + int chdir(const char *s, std::string &new_cwd, const UserPerm& perms); + void getcwd(std::string& cwd, const UserPerm& perms); // namespace ops - int opendir(const char *name, dir_result_t **dirpp); + int opendir(const char *name, dir_result_t **dirpp, const UserPerm& perms); int closedir(dir_result_t *dirp); /** @@ -955,7 +960,8 @@ class Client : public Dispatcher, public md_config_obs_t { int readdir_r(dir_result_t *dirp, struct dirent *de); int readdirplus_r(dir_result_t *dirp, struct dirent *de, struct stat *st, int *stmask); - int getdir(const char *relpath, list& names); // get the whole dir at once. + int getdir(const char *relpath, list& names, + const UserPerm& perms); // get the whole dir at once. /** * Returns the length of the buffer that got filled in, or -errno. @@ -974,75 +980,93 @@ class Client : public Dispatcher, public md_config_obs_t { loff_t telldir(dir_result_t *dirp); void seekdir(dir_result_t *dirp, loff_t offset); - int link(const char *existing, const char *newname); - int unlink(const char *path); - int rename(const char *from, const char *to); + int link(const char *existing, const char *newname, const UserPerm& perm); + int unlink(const char *path, const UserPerm& perm); + int rename(const char *from, const char *to, const UserPerm& perm); // dirs - int mkdir(const char *path, mode_t mode); - int mkdirs(const char *path, mode_t mode); - int rmdir(const char *path); + int mkdir(const char *path, mode_t mode, const UserPerm& perm); + int mkdirs(const char *path, mode_t mode, const UserPerm& perms); + int rmdir(const char *path, const UserPerm& perms); // symlinks - int readlink(const char *path, char *buf, loff_t size); + int readlink(const char *path, char *buf, loff_t size, const UserPerm& perms); - int symlink(const char *existing, const char *newname); + int symlink(const char *existing, const char *newname, const UserPerm& perms); // inode stuff unsigned statx_to_mask(unsigned int flags, unsigned int want); - int stat(const char *path, struct stat *stbuf, frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL); - int statx(const char *path, struct ceph_statx *stx, unsigned int want, unsigned int flags); - int lstat(const char *path, struct stat *stbuf, frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL); - int lstatlite(const char *path, struct statlite *buf); - - int setattr(const char *relpath, struct stat *attr, int mask); - int setattrx(const char *relpath, struct ceph_statx *stx, int mask, int flags=0); - int fsetattr(int fd, struct stat *attr, int mask); - int chmod(const char *path, mode_t mode); - int fchmod(int fd, mode_t mode); - int lchmod(const char *path, mode_t mode); - int chown(const char *path, int uid, int gid); - int fchown(int fd, int uid, int gid); - int lchown(const char *path, int uid, int gid); - int utime(const char *path, struct utimbuf *buf); - int lutime(const char *path, struct utimbuf *buf); + int stat(const char *path, struct stat *stbuf, const UserPerm& perms, + frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL); + int statx(const char *path, struct ceph_statx *stx, + const UserPerm& perms, + unsigned int want, unsigned int flags); + int lstat(const char *path, struct stat *stbuf, const UserPerm& perms, + frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL); + + int setattr(const char *relpath, struct stat *attr, int mask, + const UserPerm& perms); + int setattrx(const char *relpath, struct ceph_statx *stx, int mask, + const UserPerm& perms, int flags=0); + int fsetattr(int fd, struct stat *attr, int mask, const UserPerm& perms); + int chmod(const char *path, mode_t mode, const UserPerm& perms); + int fchmod(int fd, mode_t mode, const UserPerm& perms); + int lchmod(const char *path, mode_t mode, const UserPerm& perms); + int chown(const char *path, uid_t new_uid, gid_t new_gid, + const UserPerm& perms); + int fchown(int fd, uid_t new_uid, gid_t new_gid, const UserPerm& perms); + int lchown(const char *path, uid_t new_uid, gid_t new_gid, + const UserPerm& perms); + int utime(const char *path, struct utimbuf *buf, const UserPerm& perms); + int lutime(const char *path, struct utimbuf *buf, const UserPerm& perms); int flock(int fd, int operation, uint64_t owner); - int truncate(const char *path, loff_t size); + int truncate(const char *path, loff_t size, const UserPerm& perms); // file ops - int mknod(const char *path, mode_t mode, dev_t rdev=0); - int open(const char *path, int flags, mode_t mode=0); - int open(const char *path, int flags, mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool); - int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name); - int lookup_ino(inodeno_t ino, Inode **inode=NULL); - int lookup_parent(Inode *in, Inode **parent=NULL); - int lookup_name(Inode *in, Inode *parent); + int mknod(const char *path, mode_t mode, const UserPerm& perms, dev_t rdev=0); + int open(const char *path, int flags, const UserPerm& perms, mode_t mode=0); + int open(const char *path, int flags, const UserPerm& perms, + mode_t mode, int stripe_unit, int stripe_count, int object_size, + const char *data_pool); + int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name, + const UserPerm& perms); + int lookup_ino(inodeno_t ino, const UserPerm& perms, Inode **inode=NULL); + int lookup_parent(Inode *in, const UserPerm& perms, Inode **parent=NULL); + int lookup_name(Inode *in, Inode *parent, const UserPerm& perms); int close(int fd); - loff_t lseek(int fd, loff_t offset, int whence); + loff_t lseek(int fd, loff_t offset, int whence, const UserPerm& perms); int read(int fd, char *buf, loff_t size, loff_t offset=-1); int preadv(int fd, const struct iovec *iov, int iovcnt, loff_t offset=-1); int write(int fd, const char *buf, loff_t size, loff_t offset=-1); int pwritev(int fd, const struct iovec *iov, int iovcnt, loff_t offset=-1); int fake_write_size(int fd, loff_t size); - int ftruncate(int fd, loff_t size); + int ftruncate(int fd, loff_t size, const UserPerm& perms); int fsync(int fd, bool syncdataonly); - int fstat(int fd, struct stat *stbuf, int mask=CEPH_STAT_CAP_INODE_ALL); - int fstatx(int fd, struct ceph_statx *stx, unsigned int want, unsigned int flags); + int fstat(int fd, struct stat *stbuf, const UserPerm& perms, + int mask=CEPH_STAT_CAP_INODE_ALL); + int fstatx(int fd, struct ceph_statx *stx, const UserPerm& perms, + unsigned int want, unsigned int flags); int fallocate(int fd, int mode, loff_t offset, loff_t length); // full path xattr ops - int getxattr(const char *path, const char *name, void *value, size_t size); - int lgetxattr(const char *path, const char *name, void *value, size_t size); - int fgetxattr(int fd, const char *name, void *value, size_t size); - int listxattr(const char *path, char *list, size_t size); - int llistxattr(const char *path, char *list, size_t size); - int flistxattr(int fd, char *list, size_t size); - int removexattr(const char *path, const char *name); - int lremovexattr(const char *path, const char *name); - int fremovexattr(int fd, const char *name); - int setxattr(const char *path, const char *name, const void *value, size_t size, int flags); - int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags); - int fsetxattr(int fd, const char *name, const void *value, size_t size, int flags); + int getxattr(const char *path, const char *name, void *value, size_t size, + const UserPerm& perms); + int lgetxattr(const char *path, const char *name, void *value, size_t size, + const UserPerm& perms); + int fgetxattr(int fd, const char *name, void *value, size_t size, + const UserPerm& perms); + int listxattr(const char *path, char *list, size_t size, const UserPerm& perms); + int llistxattr(const char *path, char *list, size_t size, const UserPerm& perms); + int flistxattr(int fd, char *list, size_t size, const UserPerm& perms); + int removexattr(const char *path, const char *name, const UserPerm& perms); + int lremovexattr(const char *path, const char *name, const UserPerm& perms); + int fremovexattr(int fd, const char *name, const UserPerm& perms); + int setxattr(const char *path, const char *name, const void *value, + size_t size, int flags, const UserPerm& perms); + int lsetxattr(const char *path, const char *name, const void *value, + size_t size, int flags, const UserPerm& perms); + int fsetxattr(int fd, const char *name, const void *value, size_t size, + int flags, const UserPerm& perms); int sync_fs(); int64_t drop_caches(); @@ -1052,7 +1076,8 @@ class Client : public Dispatcher, public md_config_obs_t { int lazyio_synchronize(int fd, loff_t offset, size_t count); // expose file layout - int describe_layout(const char *path, file_layout_t* layout); + int describe_layout(const char *path, file_layout_t* layout, + const UserPerm& perms); int fdescribe_layout(int fd, file_layout_t* layout); int get_file_stripe_address(int fd, loff_t offset, vector& address); int get_file_extent_osds(int fd, loff_t off, loff_t *len, vector& osds); @@ -1068,12 +1093,12 @@ class Client : public Dispatcher, public md_config_obs_t { int enumerate_layout(int fd, vector& result, loff_t length, loff_t offset); - int mksnap(const char *path, const char *name); - int rmsnap(const char *path, const char *name); + int mksnap(const char *path, const char *name, const UserPerm& perm); + int rmsnap(const char *path, const char *name, const UserPerm& perm); // expose caps int get_caps_issued(int fd); - int get_caps_issued(const char *path); + int get_caps_issued(const char *path, const UserPerm& perms); // low-level interface v2 inodeno_t ll_get_inodeno(Inode *in) { @@ -1089,42 +1114,43 @@ class Client : public Dispatcher, public md_config_obs_t { Inode *ll_get_inode(ino_t ino); Inode *ll_get_inode(vinodeno_t vino); int ll_lookup(Inode *parent, const char *name, struct stat *attr, - Inode **out, int uid = -1, int gid = -1); + Inode **out, const UserPerm& perms); bool ll_forget(Inode *in, int count); bool ll_put(Inode *in); - int ll_getattr(Inode *in, struct stat *st, int uid = -1, int gid = -1); + int ll_getattr(Inode *in, struct stat *st, const UserPerm& perms); int ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want, - unsigned int flags, int uid = -1, int gid = -1); - int ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid = -1, - int gid = -1); - int ll_setattr(Inode *in, struct stat *st, int mask, int uid = -1, - int gid = -1); + unsigned int flags, const UserPerm& perms); + int ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, + const UserPerm& perms); + int ll_setattr(Inode *in, struct stat *st, int mask, + const UserPerm& perms); int ll_getxattr(Inode *in, const char *name, void *value, size_t size, - int uid=-1, int gid=-1); + const UserPerm& perms); int ll_setxattr(Inode *in, const char *name, const void *value, size_t size, - int flags, int uid=-1, int gid=-1); - int ll_removexattr(Inode *in, const char *name, int uid=-1, int gid=-1); - int ll_listxattr(Inode *in, char *list, size_t size, int uid=-1, int gid=-1); - int ll_opendir(Inode *in, int flags, dir_result_t **dirpp, int uid = -1, int gid = -1); + int flags, const UserPerm& perms); + int ll_removexattr(Inode *in, const char *name, const UserPerm& perms); + int ll_listxattr(Inode *in, char *list, size_t size, const UserPerm& perms); + int ll_opendir(Inode *in, int flags, dir_result_t **dirpp, + const UserPerm& perms); int ll_releasedir(dir_result_t* dirp); int ll_fsyncdir(dir_result_t* dirp); - int ll_readlink(Inode *in, char *buf, size_t bufsize, int uid = -1, int gid = -1); + int ll_readlink(Inode *in, char *buf, size_t bufsize, const UserPerm& perms); int ll_mknod(Inode *in, const char *name, mode_t mode, dev_t rdev, - struct stat *attr, Inode **out, int uid = -1, int gid = -1); + struct stat *attr, Inode **out, const UserPerm& perms); int ll_mkdir(Inode *in, const char *name, mode_t mode, struct stat *attr, - Inode **out, int uid = -1, int gid = -1); + Inode **out, const UserPerm& perm); int ll_symlink(Inode *in, const char *name, const char *value, - struct stat *attr, Inode **out, int uid = -1, int gid = -1); - int ll_unlink(Inode *in, const char *name, int uid = -1, int gid = -1); - int ll_rmdir(Inode *in, const char *name, int uid = -1, int gid = -1); + struct stat *attr, Inode **out, const UserPerm& perms); + int ll_unlink(Inode *in, const char *name, const UserPerm& perm); + int ll_rmdir(Inode *in, const char *name, const UserPerm& perms); int ll_rename(Inode *parent, const char *name, Inode *newparent, - const char *newname, int uid = -1, int gid = -1); + const char *newname, const UserPerm& perm); int ll_link(Inode *in, Inode *newparent, const char *newname, - struct stat *attr, int uid = -1, int gid = -1); - int ll_open(Inode *in, int flags, Fh **fh, int uid = -1, int gid = -1); + struct stat *attr, const UserPerm& perm); + int ll_open(Inode *in, int flags, Fh **fh, const UserPerm& perms); int ll_create(Inode *parent, const char *name, mode_t mode, int flags, - struct stat *attr, Inode **out, Fh **fhp, int uid = -1, - int gid = -1); + struct stat *attr, Inode **out, Fh **fhp, + const UserPerm& perms); int ll_read_block(Inode *in, uint64_t blockid, char *buf, uint64_t offset, uint64_t length, file_layout_t* layout); @@ -1134,17 +1160,16 @@ class Client : public Dispatcher, public md_config_obs_t { uint64_t snapseq, uint32_t sync); int ll_commit_blocks(Inode *in, uint64_t offset, uint64_t length); - int ll_statfs(Inode *in, struct statvfs *stbuf); - int ll_walk(const char* name, Inode **i, struct stat *attr); // XXX in? - int ll_listxattr_chunks(Inode *in, char *names, size_t size, - int *cookie, int *eol, int uid, int gid); + int ll_statfs(Inode *in, struct statvfs *stbuf, const UserPerm& perms); + int ll_walk(const char* name, Inode **i, struct stat *attr, + const UserPerm& perms); // XXX in? uint32_t ll_stripe_unit(Inode *in); int ll_file_layout(Inode *in, file_layout_t *layout); uint64_t ll_snap_seq(Inode *in); int ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl); int ll_write(Fh *fh, loff_t off, loff_t len, const char *data); - loff_t ll_lseek(Fh *fh, loff_t offset, int whence); + loff_t ll_lseek(Fh *fh, loff_t offset, int whence, const UserPerm& perms); int ll_flush(Fh *fh); int ll_fsync(Fh *fh, bool syncdataonly); int ll_fallocate(Fh *fh, int mode, loff_t offset, loff_t length); diff --git a/src/client/Fh.h b/src/client/Fh.h index db3a28c47a8fe..170d0e7030189 100644 --- a/src/client/Fh.h +++ b/src/client/Fh.h @@ -21,14 +21,16 @@ struct Fh { bool pos_locked; // pos is currently in use list pos_waiters; // waiters for pos + UserPerm actor_perms; // perms I opened the file with + Readahead readahead; // file lock ceph_lock_state_t *fcntl_locks; ceph_lock_state_t *flock_locks; - + Fh() : _ref(1), pos(0), mds(0), mode(0), flags(0), pos_locked(false), - readahead(), fcntl_locks(NULL), flock_locks(NULL) {} + actor_perms(), readahead(), fcntl_locks(NULL), flock_locks(NULL) {} void get() { ++_ref; } int put() { return --_ref; } }; diff --git a/src/client/Inode.cc b/src/client/Inode.cc index 0fd6c0fbab7a2..0233e15d2ccd6 100644 --- a/src/client/Inode.cc +++ b/src/client/Inode.cc @@ -7,7 +7,6 @@ #include "Dir.h" #include "MetaSession.h" #include "ClientSnapRealm.h" -#include "UserGroups.h" #include "mds/flock.h" @@ -288,6 +287,27 @@ int Inode::caps_dirty() return dirty_caps | flushing_caps; } +const UserPerm* Inode::get_best_perms() +{ + const UserPerm *perms = NULL; + for (const auto ci : caps) { + const UserPerm& iperm = ci.second->latest_perms; + if (!perms) { // we don't have any, take what's present + perms = &iperm; + } else if (iperm.uid() == uid) { + if (iperm.gid() == gid) { // we have the best possible, return + return &iperm; + } + if (perms->uid() != uid) { // take uid > gid every time + perms = &iperm; + } + } else if (perms->uid() != uid && iperm.gid() == gid) { + perms = &iperm; // a matching gid is better than nothing + } + } + return perms; +} + bool Inode::have_valid_size() { // RD+RDCACHE or WR+WRBUFFER => valid size @@ -310,12 +330,12 @@ Dir *Inode::open_dir() return dir; } -bool Inode::check_mode(uid_t ruid, UserGroups& groups, unsigned want) +bool Inode::check_mode(const UserPerm& perms, unsigned want) { - if (uid == ruid) { + if (uid == perms.uid()) { // if uid is owner, owner entry determines access want = want << 6; - } else if (groups.is_in(gid)) { + } else if (perms.gid_in_groups(gid)) { // if a gid or sgid matches the owning group, group entry determines access want = want << 3; } diff --git a/src/client/Inode.h b/src/client/Inode.h index e15c48cff05d8..64a3e50fcc67f 100644 --- a/src/client/Inode.h +++ b/src/client/Inode.h @@ -13,6 +13,7 @@ #include "include/assert.h" #include "InodeRef.h" +#include "UserPerm.h" class Client; struct MetaSession; @@ -22,7 +23,6 @@ struct SnapRealm; struct Inode; class ceph_lock_state_t; class MetaRequest; -class UserGroups; class filepath; struct Cap { @@ -37,9 +37,11 @@ struct Cap { uint64_t seq, issue_seq; __u32 mseq; // migration seq __u32 gen; + UserPerm latest_perms; Cap() : session(NULL), inode(NULL), cap_item(this), cap_id(0), issued(0), - implemented(0), wanted(0), seq(0), issue_seq(0), mseq(0), gen(0) {} + implemented(0), wanted(0), seq(0), issue_seq(0), mseq(0), gen(0), + latest_perms() {} void dump(Formatter *f) const; }; @@ -260,7 +262,7 @@ struct Inode { } }; - bool check_mode(uid_t uid, UserGroups& groups, unsigned want); + bool check_mode(const UserPerm& perms, unsigned want); // CAPS -------- void get_open_ref(int mode); @@ -279,6 +281,7 @@ struct Inode { int caps_wanted(); int caps_mds_wanted(); int caps_dirty(); + const UserPerm *get_best_perms(); bool have_valid_size(); Dir *open_dir(); diff --git a/src/client/MetaRequest.h b/src/client/MetaRequest.h index 341533ebc1e12..e0eac4a157e01 100644 --- a/src/client/MetaRequest.h +++ b/src/client/MetaRequest.h @@ -11,6 +11,7 @@ #include "include/atomic.h" #include "mds/mdstypes.h" #include "InodeRef.h" +#include "UserPerm.h" #include "messages/MClientRequest.h" @@ -69,6 +70,7 @@ struct MetaRequest { list waitfor_safe; InodeRef target; + UserPerm perms; explicit MetaRequest(int op) : _dentry(NULL), _old_dentry(NULL), abort_rc(0), @@ -169,8 +171,13 @@ struct MetaRequest { void set_filepath(const filepath& fp) { path = fp; } void set_filepath2(const filepath& fp) { path2 = fp; } void set_string2(const char *s) { path2.set_path(s, 0); } - void set_caller_uid(unsigned u) { head.caller_uid = u; } - void set_caller_gid(unsigned g) { head.caller_gid = g; } + void set_caller_perms(const UserPerm& _perms) { + perms.shallow_copy(_perms); + head.caller_uid = perms.uid(); + head.caller_gid = perms.gid(); + } + uid_t get_uid() { return perms.uid(); } + uid_t get_gid() { return perms.gid(); } void set_data(const bufferlist &d) { data = d; } void set_dentry_wanted() { head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY; diff --git a/src/client/SyntheticClient.cc b/src/client/SyntheticClient.cc index 322026751133f..77de39596471d 100644 --- a/src/client/SyntheticClient.cc +++ b/src/client/SyntheticClient.cc @@ -306,7 +306,8 @@ string SyntheticClient::get_sarg(int seq) } int SyntheticClient::run() -{ +{ + UserPerm perms = client->pick_my_perms(); dout(15) << "initing" << dendl; int err = client->init(); if (err < 0) { @@ -315,7 +316,7 @@ int SyntheticClient::run() } dout(15) << "mounting" << dendl; - err = client->mount(""); + err = client->mount("", perms); if (err < 0) { dout(0) << "failed to mount: " << cpp_strerror(err) << dendl; client->shutdown(); @@ -818,7 +819,9 @@ int SyntheticClient::run() int count = iargs.front(); iargs.pop_front(); if (run_me()) { for (int i=0; iopen("test", (rand()%2) ? (O_WRONLY|O_CREAT) : O_RDONLY); + int fd = client->open("test", (rand()%2) ? + (O_WRONLY|O_CREAT) : O_RDONLY, + perms); if (fd > 0) client->close(fd); } } @@ -830,11 +833,11 @@ int SyntheticClient::run() { int count = iargs.front(); iargs.pop_front(); if (run_me()) { - client->mknod("test", 0777); + client->mknod("test", 0777, perms); struct stat st; for (int i=0; ilstat("test", &st); - client->chmod("test", 0777); + client->lstat("test", &st, perms); + client->chmod("test", 0777, perms); } } did_run_me(); @@ -847,7 +850,7 @@ int SyntheticClient::run() sargs.push_front(file); int iarg1 = iargs.front(); iargs.pop_front(); if (run_me()) { - client->truncate(file.c_str(), iarg1); + client->truncate(file.c_str(), iarg1, perms); } did_run_me(); } @@ -876,7 +879,7 @@ int SyntheticClient::run() sscanf(diname.c_str(), "%llx", (long long unsigned*)&dirino.val); string name = get_sarg(0); if (run_me()) { - lookup_hash(ino, dirino, name.c_str()); + lookup_hash(ino, dirino, name.c_str(), perms); } } break; @@ -886,7 +889,7 @@ int SyntheticClient::run() string iname = get_sarg(0); sscanf(iname.c_str(), "%llx", (long long unsigned*)&ino.val); if (run_me()) { - lookup_ino(ino); + lookup_ino(ino, perms); } } break; @@ -896,7 +899,7 @@ int SyntheticClient::run() string base = get_sarg(0); string name = get_sarg(0); if (run_me()) - mksnap(base.c_str(), name.c_str()); + mksnap(base.c_str(), name.c_str(), perms); did_run_me(); } break; @@ -905,7 +908,7 @@ int SyntheticClient::run() string base = get_sarg(0); string name = get_sarg(0); if (run_me()) - rmsnap(base.c_str(), name.c_str()); + rmsnap(base.c_str(), name.c_str(), perms); did_run_me(); } break; @@ -997,6 +1000,7 @@ void SyntheticClient::up() int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) { dout(4) << "play trace prefix '" << prefix << "'" << dendl; + UserPerm perms = client->pick_my_perms(); t.start(); char buf[1024]; @@ -1018,10 +1022,10 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) // prefix? const char *p = prefix.c_str(); if (prefix.length()) { - client->mkdir(prefix.c_str(), 0755); + client->mkdir(prefix.c_str(), 0755, perms); struct stat attr; i1 = client->ll_get_inode(vinodeno_t(1, CEPH_NOSNAP)); - if (client->ll_lookup(i1, prefix.c_str(), &attr, &i2) == 0) { + if (client->ll_lookup(i1, prefix.c_str(), &attr, &i2, perms) == 0) { ll_inos[1] = attr.st_ino; dout(5) << "'root' ino is " << inodeno_t(attr.st_ino) << dendl; client->ll_put(i1); @@ -1068,32 +1072,33 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) } // high level ops --------------------- + UserPerm perms = client->pick_my_perms(); if (strcmp(op, "link") == 0) { const char *a = t.get_string(buf, p); const char *b = t.get_string(buf2, p); - client->link(a,b); + client->link(a, b, perms); } else if (strcmp(op, "unlink") == 0) { const char *a = t.get_string(buf, p); - client->unlink(a); + client->unlink(a, perms); } else if (strcmp(op, "rename") == 0) { const char *a = t.get_string(buf, p); const char *b = t.get_string(buf2, p); - client->rename(a,b); + client->rename(a,b, perms); } else if (strcmp(op, "mkdir") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); - client->mkdir(a, b); + client->mkdir(a, b, perms); } else if (strcmp(op, "rmdir") == 0) { const char *a = t.get_string(buf, p); - client->rmdir(a); + client->rmdir(a, perms); } else if (strcmp(op, "symlink") == 0) { const char *a = t.get_string(buf, p); const char *b = t.get_string(buf2, p); - client->symlink(a,b); + client->symlink(a, b, perms); } else if (strcmp(op, "readlink") == 0) { const char *a = t.get_string(buf, p); char buf[100]; - client->readlink(a, buf, 100); + client->readlink(a, buf, 100, perms); } else if (strcmp(op, "lstat") == 0) { struct stat st; const char *a = t.get_string(buf, p); @@ -1101,16 +1106,16 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) strcmp(a, "/") != 0 && strcmp(a, "/lib") != 0 && // or /lib.. that would be a lookup. hack. a[0] != 0) // stop stating the root directory already - client->lstat(a, &st); + client->lstat(a, &st, perms); } else if (strcmp(op, "chmod") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); - client->chmod(a, b); + client->chmod(a, b, perms); } else if (strcmp(op, "chown") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); int64_t c = t.get_int(); - client->chown(a, b, c); + client->chown(a, b, c, perms); } else if (strcmp(op, "utime") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); @@ -1118,20 +1123,20 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) struct utimbuf u; u.actime = b; u.modtime = c; - client->utime(a, &u); + client->utime(a, &u, perms); } else if (strcmp(op, "mknod") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); int64_t c = t.get_int(); - client->mknod(a, b, c); + client->mknod(a, b, perms, c); } else if (strcmp(op, "oldmknod") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); - client->mknod(a, b, 0); + client->mknod(a, b, perms, 0); } else if (strcmp(op, "getdir") == 0) { const char *a = t.get_string(buf, p); list contents; - int r = client->getdir(a, contents); + int r = client->getdir(a, contents, perms); if (r < 0) { dout(1) << "getdir on " << a << " returns " << r << dendl; } @@ -1139,7 +1144,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) const char *a = t.get_string(buf, p); int64_t b = t.get_int(); dir_result_t *dirp; - client->opendir(a, &dirp); + client->opendir(a, &dirp, perms); if (dirp) open_dirs[b] = dirp; } else if (strcmp(op, "closedir") == 0) { int64_t a = t.get_int(); @@ -1150,13 +1155,13 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) int64_t b = t.get_int(); int64_t c = t.get_int(); int64_t d = t.get_int(); - int64_t fd = client->open(a, b, c); + int64_t fd = client->open(a, b, perms, c); if (fd > 0) open_files[d] = fd; } else if (strcmp(op, "oldopen") == 0) { const char *a = t.get_string(buf, p); int64_t b = t.get_int(); int64_t d = t.get_int(); - int64_t fd = client->open(a, b, 0755); + int64_t fd = client->open(a, b, perms, 0755); if (fd > 0) open_files[d] = fd; } else if (strcmp(op, "close") == 0) { int64_t id = t.get_int(); @@ -1168,7 +1173,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) int fd = open_files[f]; int64_t off = t.get_int(); int64_t whence = t.get_int(); - client->lseek(fd, off, whence); + client->lseek(fd, off, whence, perms); } else if (strcmp(op, "read") == 0) { int64_t f = t.get_int(); int64_t size = t.get_int(); @@ -1195,12 +1200,12 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) } else if (strcmp(op, "truncate") == 0) { const char *a = t.get_string(buf, p); int64_t l = t.get_int(); - client->truncate(a, l); + client->truncate(a, l, perms); } else if (strcmp(op, "ftruncate") == 0) { int64_t f = t.get_int(); int fd = open_files[f]; int64_t l = t.get_int(); - client->ftruncate(fd, l); + client->ftruncate(fd, l, perms); } else if (strcmp(op, "fsync") == 0) { int64_t f = t.get_int(); int64_t b = t.get_int(); @@ -1211,10 +1216,10 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) // Client users should remember their path, but since this // is just a synthetic client we ignore it. std::string ignore; - client->chdir(a, ignore); + client->chdir(a, ignore, perms); } else if (strcmp(op, "statfs") == 0) { struct statvfs stbuf; - client->statfs("/", &stbuf); + client->statfs("/", &stbuf, perms); } // low level ops --------------------- @@ -1225,7 +1230,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - if (client->ll_lookup(i1, name, &attr, &i2) == 0) + if (client->ll_lookup(i1, name, &attr, &i2, perms) == 0) ll_inos[r] = attr.st_ino; client->ll_put(i1); } @@ -1241,7 +1246,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - client->ll_getattr(i1, &attr); + client->ll_getattr(i1, &attr, perms); client->ll_put(i1); } } else if (strcmp(op, "ll_setattr") == 0) { @@ -1257,7 +1262,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) int mask = t.get_int(); if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - client->ll_setattr(i1, &attr, mask); + client->ll_setattr(i1, &attr, mask, perms); client->ll_put(i1); } } else if (strcmp(op, "ll_readlink") == 0) { @@ -1265,7 +1270,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) if (ll_inos.count(i)) { char buf[PATH_MAX]; i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - client->ll_readlink(i1, buf, sizeof(buf)); + client->ll_readlink(i1, buf, sizeof(buf), perms); client->ll_put(i1); } } else if (strcmp(op, "ll_mknod") == 0) { @@ -1277,7 +1282,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - if (client->ll_mknod(i1, n, m, r, &attr, &i2) == 0) + if (client->ll_mknod(i1, n, m, r, &attr, &i2, perms) == 0) ll_inos[ri] = attr.st_ino; client->ll_put(i1); } @@ -1289,7 +1294,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - if (client->ll_mkdir(i1, n, m, &attr, &i2) == 0) + if (client->ll_mkdir(i1, n, m, &attr, &i2, perms) == 0) ll_inos[ri] = attr.st_ino; client->ll_put(i1); } @@ -1301,7 +1306,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) struct stat attr; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - if (client->ll_symlink(i1, n, v, &attr, &i2) == 0) + if (client->ll_symlink(i1, n, v, &attr, &i2, perms) == 0) ll_inos[ri] = attr.st_ino; client->ll_put(i1); } @@ -1310,7 +1315,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) const char *n = t.get_string(buf, p); if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - client->ll_unlink(i1, n); + client->ll_unlink(i1, n, perms); client->ll_put(i1); } } else if (strcmp(op, "ll_rmdir") == 0) { @@ -1318,7 +1323,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) const char *n = t.get_string(buf, p); if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - client->ll_rmdir(i1, n); + client->ll_rmdir(i1, n, perms); client->ll_put(i1); } } else if (strcmp(op, "ll_rename") == 0) { @@ -1330,7 +1335,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) ll_inos.count(ni)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); i2 = client->ll_get_inode(vinodeno_t(ll_inos[ni],CEPH_NOSNAP)); - client->ll_rename(i1, n, i2, nn); + client->ll_rename(i1, n, i2, nn, perms); client->ll_put(i1); client->ll_put(i2); } @@ -1343,7 +1348,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) ll_inos.count(ni)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); i2 = client->ll_get_inode(vinodeno_t(ll_inos[ni],CEPH_NOSNAP)); - client->ll_link(i1, i2, nn, &attr); + client->ll_link(i1, i2, nn, &attr, perms); client->ll_put(i1); client->ll_put(i2); } @@ -1353,7 +1358,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) dir_result_t *dirp; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - if (client->ll_opendir(i1, O_RDONLY, &dirp) == 0) + if (client->ll_opendir(i1, O_RDONLY, &dirp, perms) == 0) ll_dirs[r] = dirp; client->ll_put(i1); } @@ -1370,7 +1375,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) Fh *fhp; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - if (client->ll_open(i1, f, &fhp) == 0) + if (client->ll_open(i1, f, &fhp, perms) == 0) ll_files[r] = fhp; client->ll_put(i1); } @@ -1385,7 +1390,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) if (ll_inos.count(i)) { Fh *fhp; i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - if (client->ll_create(i1, n, m, f, &attr, NULL, &fhp) == 0) { + if (client->ll_create(i1, n, m, f, &attr, NULL, &fhp, perms) == 0) { ll_inos[ri] = attr.st_ino; ll_files[r] = fhp; } @@ -1434,7 +1439,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) } else if (strcmp(op, "ll_statfs") == 0) { int64_t i = t.get_int(); if (ll_inos.count(i)) - {} //client->ll_statfs(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); + {} //client->ll_statfs(vinodeno_t(ll_inos[i],CEPH_NOSNAP), perms); } @@ -1556,7 +1561,8 @@ int SyntheticClient::clean_dir(string& basedir) { // read dir list contents; - int r = client->getdir(basedir.c_str(), contents); + UserPerm perms = client->pick_my_perms(); + int r = client->getdir(basedir.c_str(), contents, perms); if (r < 0) { dout(1) << "getdir on " << basedir << " returns " << r << dendl; return r; @@ -1572,7 +1578,7 @@ int SyntheticClient::clean_dir(string& basedir) if (time_to_stop()) break; struct stat st; - int r = client->lstat(file.c_str(), &st); + int r = client->lstat(file.c_str(), &st, perms); if (r < 0) { dout(1) << "stat error on " << file << " r=" << r << dendl; continue; @@ -1580,9 +1586,9 @@ int SyntheticClient::clean_dir(string& basedir) if ((st.st_mode & S_IFMT) == S_IFDIR) { clean_dir(file); - client->rmdir(file.c_str()); + client->rmdir(file.c_str(), perms); } else { - client->unlink(file.c_str()); + client->unlink(file.c_str(), perms); } } @@ -1605,6 +1611,7 @@ int SyntheticClient::full_walk(string& basedir) ceph::unordered_map nlink; ceph::unordered_map nlink_seen; + UserPerm perms = client->pick_my_perms(); while (!dirq.empty()) { string dir = dirq.front(); frag_info_t expect = statq.front(); @@ -1615,7 +1622,7 @@ int SyntheticClient::full_walk(string& basedir) // read dir list contents; - int r = client->getdir(dir.c_str(), contents); + int r = client->getdir(dir.c_str(), contents, perms); if (r < 0) { dout(1) << "getdir on " << dir << " returns " << r << dendl; continue; @@ -1631,7 +1638,7 @@ int SyntheticClient::full_walk(string& basedir) struct stat st; frag_info_t dirstat; - int r = client->lstat(file.c_str(), &st, &dirstat); + int r = client->lstat(file.c_str(), &st, perms, &dirstat); if (r < 0) { dout(1) << "stat error on " << file << " r=" << r << dendl; continue; @@ -1692,16 +1699,18 @@ int SyntheticClient::full_walk(string& basedir) int SyntheticClient::dump_placement(string& fn) { + + UserPerm perms = client->pick_my_perms(); // open file - int fd = client->open(fn.c_str(), O_RDONLY); + int fd = client->open(fn.c_str(), O_RDONLY, perms); dout(5) << "reading from " << fn << " fd " << fd << dendl; if (fd < 0) return fd; // How big is it? struct stat stbuf; - int lstat_result = client->lstat(fn.c_str(), &stbuf); + int lstat_result = client->lstat(fn.c_str(), &stbuf, perms); if (lstat_result < 0) { dout(0) << "lstat error for file " << fn << dendl; client->close(fd); @@ -1739,8 +1748,9 @@ int SyntheticClient::make_dirs(const char *basedir, int dirs, int files, int dep { if (time_to_stop()) return 0; + UserPerm perms = client->pick_my_perms(); // make sure base dir exists - int r = client->mkdir(basedir, 0755); + int r = client->mkdir(basedir, 0755, perms); if (r != 0) { dout(1) << "can't make base dir? " << basedir << dendl; //return -1; @@ -1751,7 +1761,7 @@ int SyntheticClient::make_dirs(const char *basedir, int dirs, int files, int dep dout(3) << "make_dirs " << basedir << " dirs " << dirs << " files " << files << " depth " << depth << dendl; for (int i=0; imknod(d, 0644); + client->mknod(d, 0644, perms); } if (depth == 0) return 0; @@ -1768,9 +1778,11 @@ int SyntheticClient::stat_dirs(const char *basedir, int dirs, int files, int dep { if (time_to_stop()) return 0; + UserPerm perms = client->pick_my_perms(); + // make sure base dir exists struct stat st; - int r = client->lstat(basedir, &st); + int r = client->lstat(basedir, &st, perms); if (r != 0) { dout(1) << "can't make base dir? " << basedir << dendl; return -1; @@ -1781,7 +1793,7 @@ int SyntheticClient::stat_dirs(const char *basedir, int dirs, int files, int dep dout(3) << "stat_dirs " << basedir << " dirs " << dirs << " files " << files << " depth " << depth << dendl; for (int i=0; ilstat(d, &st); + client->lstat(d, &st, perms); } if (depth == 0) return 0; @@ -1804,8 +1816,9 @@ int SyntheticClient::read_dirs(const char *basedir, int dirs, int files, int dep dout(3) << "read_dirs " << basedir << " dirs " << dirs << " files " << files << " depth " << depth << dendl; list contents; + UserPerm perms = client->pick_my_perms(); utime_t s = ceph_clock_now(client->cct); - int r = client->getdir(basedir, contents); + int r = client->getdir(basedir, contents, perms); utime_t e = ceph_clock_now(client->cct); e -= s; if (r < 0) { @@ -1816,7 +1829,7 @@ int SyntheticClient::read_dirs(const char *basedir, int dirs, int files, int dep for (int i=0; icct); - if (client->lstat(d, &st) < 0) { + if (client->lstat(d, &st, perms) < 0) { dout(2) << "read_dirs failed stat on " << d << ", stopping" << dendl; return -1; } @@ -1838,18 +1851,19 @@ int SyntheticClient::make_files(int num, int count, int priv, bool more) { int whoami = client->get_nodeid().v; char d[255]; + UserPerm perms = client->pick_my_perms(); if (priv) { for (int c=0; cmkdir(d, 0755); + client->mkdir(d, 0755, perms); } } else { // shared if (true || whoami == 0) { for (int c=0; cmkdir(d, 0755); + client->mkdir(d, 0755, perms); } } else { sleep(2); @@ -1863,12 +1877,12 @@ int SyntheticClient::make_files(int num, int count, int priv, bool more) for (int n=0; nmknod(d, 0644); + client->mknod(d, 0644, perms); if (more) { - client->lstat(d, &st); - int fd = client->open(d, O_RDONLY); - client->unlink(d); + client->lstat(d, &st, perms); + int fd = client->open(d, O_RDONLY, perms); + client->unlink(d, perms); client->close(fd); } @@ -1887,16 +1901,18 @@ int SyntheticClient::link_test() char d[255]; char e[255]; + UserPerm perms = client->pick_my_perms(); + // create files int num = 200; - client->mkdir("orig", 0755); - client->mkdir("copy", 0755); + client->mkdir("orig", 0755, perms); + client->mkdir("copy", 0755, perms); utime_t start = ceph_clock_now(client->cct); for (int i=0; imknod(d, 0755); + client->mknod(d, 0755, perms); } utime_t end = ceph_clock_now(client->cct); end -= start; @@ -1908,7 +1924,7 @@ int SyntheticClient::link_test() for (int i=0; ilink(d, e); + client->link(d, e, perms); } end = ceph_clock_now(client->cct); end -= start; @@ -1921,11 +1937,12 @@ int SyntheticClient::link_test() int SyntheticClient::create_shared(int num) { // files + UserPerm perms = client->pick_my_perms(); char d[255]; - client->mkdir("test", 0755); + client->mkdir("test", 0755, perms); for (int n=0; nmknod(d, 0644); + client->mknod(d, 0644, perms); } return 0; @@ -1935,19 +1952,20 @@ int SyntheticClient::open_shared(int num, int count) { // files char d[255]; + UserPerm perms = client->pick_my_perms(); for (int c=0; c fds; for (int n=0; nopen(d,O_RDONLY); + int fd = client->open(d, O_RDONLY, perms); if (fd > 0) fds.push_back(fd); } if (false && client->get_nodeid() == 0) for (int n=0; nunlink(d); + client->unlink(d, perms); } while (!fds.empty()) { @@ -1963,7 +1981,7 @@ int SyntheticClient::open_shared(int num, int count) // Hits OSD 0 with writes to various files with OSD 0 as the primary. int SyntheticClient::overload_osd_0(int n, int size, int wrsize) { - + UserPerm perms = client->pick_my_perms(); // collect a bunch of files starting on OSD 0 int left = n; int tried = 0; @@ -1974,7 +1992,7 @@ int SyntheticClient::overload_osd_0(int n, int size, int wrsize) { dout(0) << "in OSD overload" << dendl; string filename = get_sarg(tried); dout(1) << "OSD Overload workload: trying file " << filename << dendl; - int fd = client->open(filename.c_str(), O_RDWR|O_CREAT); + int fd = client->open(filename.c_str(), O_RDWR|O_CREAT, perms); ++tried; // only use the file if its first primary is OSD 0 @@ -2010,7 +2028,8 @@ int SyntheticClient::check_first_primary(int fh) int SyntheticClient::rm_file(string& fn) { - return client->unlink(fn.c_str()); + UserPerm perms = client->pick_my_perms(); + return client->unlink(fn.c_str(), perms); } int SyntheticClient::write_file(string& fn, int size, loff_t wrsize) // size is in MB, wrsize in bytes @@ -2019,8 +2038,9 @@ int SyntheticClient::write_file(string& fn, int size, loff_t wrsize) // size i char *buf = new char[wrsize+100]; // 1 MB memset(buf, 7, wrsize); int64_t chunks = (uint64_t)size * (uint64_t)(1024*1024) / (uint64_t)wrsize; + UserPerm perms = client->pick_my_perms(); - int fd = client->open(fn.c_str(), O_RDWR|O_CREAT); + int fd = client->open(fn.c_str(), O_RDWR|O_CREAT, perms); dout(5) << "writing to " << fn << " fd " << fd << dendl; if (fd < 0) { delete[] buf; @@ -2135,8 +2155,9 @@ int SyntheticClient::read_file(const std::string& fn, int size, char *buf = new char[rdsize]; memset(buf, 1, rdsize); uint64_t chunks = (uint64_t)size * (uint64_t)(1024*1024) / (uint64_t)rdsize; + UserPerm perms = client->pick_my_perms(); - int fd = client->open(fn.c_str(), O_RDONLY); + int fd = client->open(fn.c_str(), O_RDONLY, perms); dout(5) << "reading from " << fn << " fd " << fd << dendl; if (fd < 0) { delete[] buf; @@ -2406,8 +2427,9 @@ int SyntheticClient::object_rw(int nobj, int osize, int wrpc, int SyntheticClient::read_random(string& fn, int size, int rdsize) // size is in MB, wrsize in bytes { + UserPerm perms = client->pick_my_perms(); uint64_t chunks = (uint64_t)size * (uint64_t)(1024*1024) / (uint64_t)rdsize; - int fd = client->open(fn.c_str(), O_RDWR); + int fd = client->open(fn.c_str(), O_RDWR, perms); dout(5) << "reading from " << fn << " fd " << fd << dendl; if (fd < 0) return fd; @@ -2535,7 +2557,8 @@ int normdist(int min, int max, int stdev) /* specifies input values */ int SyntheticClient::read_random_ex(string& fn, int size, int rdsize) // size is in MB, wrsize in bytes { uint64_t chunks = (uint64_t)size * (uint64_t)(1024*1024) / (uint64_t)rdsize; - int fd = client->open(fn.c_str(), O_RDWR); + UserPerm perms = client->pick_my_perms(); + int fd = client->open(fn.c_str(), O_RDWR, perms); dout(5) << "reading from " << fn << " fd " << fd << dendl; if (fd < 0) return fd; @@ -2638,6 +2661,7 @@ int SyntheticClient::random_walk(int num_req) init_op_dist(); // set up metadata op distribution + UserPerm perms = client->pick_my_perms(); while (left > 0) { left--; @@ -2680,26 +2704,26 @@ int SyntheticClient::random_walk(int num_req) if (contents.empty()) op = CEPH_MDS_OP_READDIR; else - r = client->unlink( get_random_sub() ); // will fail on dirs + r = client->unlink(get_random_sub(), perms); // will fail on dirs } if (op == CEPH_MDS_OP_RENAME) { if (contents.empty()) op = CEPH_MDS_OP_READDIR; else { - r = client->rename( get_random_sub(), make_sub("ren") ); + r = client->rename(get_random_sub(), make_sub("ren"), perms); } } if (op == CEPH_MDS_OP_MKDIR) { - r = client->mkdir( make_sub("mkdir"), 0755); + r = client->mkdir(make_sub("mkdir"), 0755, perms); } if (op == CEPH_MDS_OP_RMDIR) { if (!subdirs.empty()) - r = client->rmdir( get_random_subdir() ); + r = client->rmdir(get_random_subdir(), perms); else - r = client->rmdir( cwd.c_str() ); // will pbly fail + r = client->rmdir(cwd.c_str(), perms); // will pbly fail } if (op == CEPH_MDS_OP_SYMLINK) { @@ -2709,36 +2733,36 @@ int SyntheticClient::random_walk(int num_req) if (contents.empty()) op = CEPH_MDS_OP_READDIR; else - r = client->chmod( get_random_sub(), rand() & 0755 ); + r = client->chmod(get_random_sub(), rand() & 0755, perms); } if (op == CEPH_MDS_OP_CHOWN) { - if (contents.empty()) r = client->chown( cwd.c_str(), rand(), rand() ); + if (contents.empty()) r = client->chown(cwd.c_str(), rand(), rand(), perms); else - r = client->chown( get_random_sub(), rand(), rand() ); + r = client->chown(get_random_sub(), rand(), rand(), perms); } if (op == CEPH_MDS_OP_UTIME) { struct utimbuf b; memset(&b, 1, sizeof(b)); if (contents.empty()) - r = client->utime( cwd.c_str(), &b ); + r = client->utime(cwd.c_str(), &b, perms); else - r = client->utime( get_random_sub(), &b ); + r = client->utime(get_random_sub(), &b, perms); } */ if (op == CEPH_MDS_OP_LINK) { } if (op == CEPH_MDS_OP_MKNOD) { - r = client->mknod( make_sub("mknod"), 0644); + r = client->mknod(make_sub("mknod"), 0644, perms); } if (op == CEPH_MDS_OP_OPEN) { if (contents.empty()) op = CEPH_MDS_OP_READDIR; else { - r = client->open( get_random_sub(), O_RDONLY ); + r = client->open(get_random_sub(), O_RDONLY, perms); if (r > 0) { assert(open_files.count(r) == 0); open_files.insert(r); @@ -2770,14 +2794,14 @@ int SyntheticClient::random_walk(int num_req) } else op = CEPH_MDS_OP_READDIR; } else - r = client->lstat(get_random_sub(), &st); + r = client->lstat(get_random_sub(), &st, perms); } if (op == CEPH_MDS_OP_READDIR) { clear_dir(); list c; - r = client->getdir( cwd.c_str(), c ); + r = client->getdir(cwd.c_str(), c, perms); for (list::iterator it = c.begin(); it != c.end(); @@ -2824,12 +2848,13 @@ int SyntheticClient::random_walk(int num_req) void SyntheticClient::make_dir_mess(const char *basedir, int n) { + UserPerm perms = client->pick_my_perms(); vector dirs; dirs.push_back(basedir); dirs.push_back(basedir); - client->mkdir(basedir, 0755); + client->mkdir(basedir, 0755, perms); // motivation: // P(dir) ~ subdirs_of(dir) + 2 @@ -2852,7 +2877,7 @@ void SyntheticClient::make_dir_mess(const char *basedir, int n) dirs.push_back(dir); // do it - client->mkdir(dir.c_str(), 0755); + client->mkdir(dir.c_str(), 0755, perms); } @@ -2862,24 +2887,26 @@ void SyntheticClient::make_dir_mess(const char *basedir, int n) void SyntheticClient::foo() { + UserPerm perms = client->pick_my_perms(); + if (1) { // make 2 parallel dirs, link/unlink between them. char a[100], b[100]; - client->mkdir("/a", 0755); - client->mkdir("/b", 0755); + client->mkdir("/a", 0755, perms); + client->mkdir("/b", 0755, perms); for (int i=0; i<10; i++) { snprintf(a, sizeof(a), "/a/%d", i); - client->mknod(a, 0644); + client->mknod(a, 0644, perms); } while (1) { for (int i=0; i<10; i++) { snprintf(a, sizeof(a), "/a/%d", i); snprintf(b, sizeof(b), "/b/%d", i); - client->link(a, b); + client->link(a, b, perms); } for (int i=0; i<10; i++) { snprintf(b, sizeof(b), "/b/%d", i); - client->unlink(b); + client->unlink(b, perms); } } return; @@ -2888,15 +2915,15 @@ void SyntheticClient::foo() // bug1.cpp const char *fn = "blah"; char buffer[8192]; - client->unlink(fn); - int handle = client->open(fn,O_CREAT|O_RDWR,S_IRWXU); + client->unlink(fn, perms); + int handle = client->open(fn, O_CREAT|O_RDWR, perms, S_IRWXU); assert(handle>=0); int r=client->write(handle,buffer,8192); assert(r>=0); r=client->close(handle); assert(r>=0); - handle = client->open(fn,O_RDWR); // open the same file, it must have some data already + handle = client->open(fn, O_RDWR, perms); // open the same file, it must have some data already assert(handle>=0); r=client->read(handle,buffer,8192); assert(r==8192); // THIS ASSERTION FAILS with disabled cache @@ -2907,13 +2934,13 @@ void SyntheticClient::foo() } if (1) { dout(0) << "first" << dendl; - int fd = client->open("tester", O_WRONLY|O_CREAT); + int fd = client->open("tester", O_WRONLY|O_CREAT, perms); client->write(fd, "hi there", 0, 8); client->close(fd); dout(0) << "sleep" << dendl; sleep(10); dout(0) << "again" << dendl; - fd = client->open("tester", O_WRONLY|O_CREAT); + fd = client->open("tester", O_WRONLY|O_CREAT, perms); client->write(fd, "hi there", 0, 8); client->close(fd); return; @@ -2929,7 +2956,7 @@ void SyntheticClient::foo() char src[80]; snprintf(src, sizeof(src), "syn.0.0/dir.%d/dir.%d/file.%d", a, b, c); //int fd = - client->open(src, O_RDONLY); + client->open(src, O_RDONLY, perms); } return; @@ -2949,7 +2976,7 @@ void SyntheticClient::foo() char dst[80]; snprintf(src, sizeof(src), "syn.0.0/dir.%d/dir.%d/file.%d", a, b, c); snprintf(dst, sizeof(dst), "syn.0.0/dir.%d/dir.%d/file.%d", d, e, f); - client->rename(src, dst); + client->rename(src, dst, perms); } return; } @@ -2969,7 +2996,7 @@ void SyntheticClient::foo() char dst[80]; snprintf(src, sizeof(src), "syn.0.0/dir.%d/dir.%d/file.%d", a, b, c); snprintf(dst, sizeof(dst), "syn.0.0/dir.%d/dir.%d/newlink.%d", d, e, f); - client->link(src, dst); + client->link(src, dst, perms); } srand(0); for (int i=0; i<100; i++) { @@ -2984,7 +3011,7 @@ void SyntheticClient::foo() char dst[80]; snprintf(src, sizeof(src), "syn.0.0/dir.%d/dir.%d/file.%d", a, b, c); snprintf(dst, sizeof(dst), "syn.0.0/dir.%d/dir.%d/newlink.%d", d, e, f); - client->unlink(dst); + client->unlink(dst, perms); } @@ -2992,61 +3019,61 @@ void SyntheticClient::foo() } // link fun - client->mknod("one", 0755); - client->mknod("two", 0755); - client->link("one", "three"); - client->mkdir("dir", 0755); - client->link("two", "/dir/twolink"); - client->link("dir/twolink", "four"); + client->mknod("one", 0755, perms); + client->mknod("two", 0755, perms); + client->link("one", "three", perms); + client->mkdir("dir", 0755, perms); + client->link("two", "/dir/twolink", perms); + client->link("dir/twolink", "four", perms); // unlink fun - client->mknod("a", 0644); - client->unlink("a"); - client->mknod("b", 0644); - client->link("b", "c"); - client->unlink("c"); - client->mkdir("d", 0755); - client->unlink("d"); - client->rmdir("d"); + client->mknod("a", 0644, perms); + client->unlink("a", perms); + client->mknod("b", 0644, perms); + client->link("b", "c", perms); + client->unlink("c", perms); + client->mkdir("d", 0755, perms); + client->unlink("d", perms); + client->rmdir("d", perms); // rename fun - client->mknod("p1", 0644); - client->mknod("p2", 0644); - client->rename("p1","p2"); - client->mknod("p3", 0644); - client->rename("p3","p4"); + client->mknod("p1", 0644, perms); + client->mknod("p2", 0644, perms); + client->rename("p1","p2", perms); + client->mknod("p3", 0644, perms); + client->rename("p3","p4", perms); // check dest dir ambiguity thing - client->mkdir("dir1", 0755); - client->mkdir("dir2", 0755); - client->rename("p2","dir1/p2"); - client->rename("dir1/p2","dir2/p2"); - client->rename("dir2/p2","/p2"); + client->mkdir("dir1", 0755, perms); + client->mkdir("dir2", 0755, perms); + client->rename("p2", "dir1/p2", perms); + client->rename("dir1/p2", "dir2/p2", perms); + client->rename("dir2/p2", "/p2", perms); // check primary+remote link merging - client->link("p2","p2.l"); - client->link("p4","p4.l"); - client->rename("p2.l","p2"); - client->rename("p4","p4.l"); + client->link("p2","p2.l", perms); + client->link("p4","p4.l", perms); + client->rename("p2.l", "p2", perms); + client->rename("p4", "p4.l", perms); // check anchor updates - client->mknod("dir1/a", 0644); - client->link("dir1/a", "da1"); - client->link("dir1/a", "da2"); - client->link("da2","da3"); - client->rename("dir1/a","dir2/a"); - client->rename("dir2/a","da2"); - client->rename("da1","da2"); - client->rename("da2","da3"); + client->mknod("dir1/a", 0644, perms); + client->link("dir1/a", "da1", perms); + client->link("dir1/a", "da2", perms); + client->link("da2","da3", perms); + client->rename("dir1/a", "dir2/a", perms); + client->rename("dir2/a", "da2", perms); + client->rename("da1", "da2", perms); + client->rename("da2", "da3", perms); // check directory renames - client->mkdir("dir3", 0755); - client->mknod("dir3/asdf", 0644); - client->mkdir("dir4", 0755); - client->mkdir("dir5", 0755); - client->mknod("dir5/asdf", 0644); - client->rename("dir3","dir4"); // ok - client->rename("dir4","dir5"); // fail + client->mkdir("dir3", 0755, perms); + client->mknod("dir3/asdf", 0644, perms); + client->mkdir("dir4", 0755, perms); + client->mkdir("dir5", 0755, perms); + client->mknod("dir5/asdf", 0644, perms); + client->rename("dir3", "dir4", perms); // ok + client->rename("dir4", "dir5", perms); // fail } int SyntheticClient::thrash_links(const char *basedir, int dirs, int files, int depth, int n) @@ -3057,6 +3084,8 @@ int SyntheticClient::thrash_links(const char *basedir, int dirs, int files, int if (time_to_stop()) return 0; + UserPerm perms = client->pick_my_perms(); + srand(0); if (1) { bool renames = true; // thrash renames too? @@ -3084,9 +3113,9 @@ int SyntheticClient::thrash_links(const char *basedir, int dirs, int files, int } } - if (client->rename(dst.c_str(), "/tmp") == 0) { - client->rename(src.c_str(), dst.c_str()); - client->rename("/tmp", src.c_str()); + if (client->rename(dst.c_str(), "/tmp", perms) == 0) { + client->rename(src.c_str(), dst.c_str(), perms); + client->rename("/tmp", src.c_str(), perms); } continue; } @@ -3120,18 +3149,18 @@ int SyntheticClient::thrash_links(const char *basedir, int dirs, int files, int int o = rand() % 4; switch (o) { case 0: - client->mknod(src.c_str(), 0755); - if (renames) client->rename(src.c_str(), dst.c_str()); + client->mknod(src.c_str(), 0755, perms); + if (renames) client->rename(src.c_str(), dst.c_str(), perms); break; case 1: - client->mknod(src.c_str(), 0755); - client->unlink(dst.c_str()); - client->link(src.c_str(), dst.c_str()); + client->mknod(src.c_str(), 0755, perms); + client->unlink(dst.c_str(), perms); + client->link(src.c_str(), dst.c_str(), perms); break; - case 2: client->unlink(src.c_str()); break; - case 3: client->unlink(dst.c_str()); break; - //case 4: client->mknod(src.c_str(), 0755); break; - //case 5: client->mknod(dst.c_str(), 0755); break; + case 2: client->unlink(src.c_str(), perms); break; + case 3: client->unlink(dst.c_str(), perms); break; + //case 4: client->mknod(src.c_str(), 0755, perms); break; + //case 5: client->mknod(dst.c_str(), 0755, perms); break; } } return 0; @@ -3169,7 +3198,7 @@ int SyntheticClient::thrash_links(const char *basedir, int dirs, int files, int snprintf(f, sizeof(f), "/ln.%d", i); ln += f; - client->link(file.c_str(), ln.c_str()); + client->link(file.c_str(), ln.c_str(), perms); } } return 0; @@ -3190,8 +3219,10 @@ void SyntheticClient::import_find(const char *base, const char *find, bool data) * */ + UserPerm process_perms = client->pick_my_perms(); + if (base[0] != '-') - client->mkdir(base, 0755); + client->mkdir(base, 0755, process_perms); ifstream f(find); assert(f.is_open()); @@ -3217,6 +3248,7 @@ void SyntheticClient::import_find(const char *base, const char *find, bool data) f >> mtime; f.seekg(1, ios::cur); getline(f, filename); + UserPerm perms(uid, gid); // ignore "." if (filename == ".") continue; @@ -3275,7 +3307,7 @@ void SyntheticClient::import_find(const char *base, const char *find, bool data) target = filename.substr(pos + 4); } dout(10) << "symlink from '" << link << "' -> '" << target << "'" << dendl; - client->symlink(target.c_str(), link.c_str()); + client->symlink(target.c_str(), link.c_str(), perms); } else { string f; if (base[0] != '-') { @@ -3284,24 +3316,24 @@ void SyntheticClient::import_find(const char *base, const char *find, bool data) } f += filename; if (S_ISDIR(mode)) { - client->mkdir(f.c_str(), mode); + client->mkdir(f.c_str(), mode, perms); } else { - int fd = client->open(f.c_str(), O_WRONLY|O_CREAT, mode & 0777); + int fd = client->open(f.c_str(), O_WRONLY|O_CREAT, perms, mode & 0777); assert(fd > 0); if (data) { client->write(fd, "", 0, size); } else { - client->truncate(f.c_str(), size); + client->truncate(f.c_str(), size, perms); } client->close(fd); - //client->chmod(f.c_str(), mode & 0777); - client->chown(f.c_str(), uid, gid); + //client->chmod(f.c_str(), mode & 0777, perms, process_perms); + client->chown(f.c_str(), uid, gid, process_perms); struct utimbuf ut; ut.modtime = mtime; ut.actime = mtime; - client->utime(f.c_str(), &ut); + client->utime(f.c_str(), &ut, perms); } } } @@ -3310,28 +3342,30 @@ void SyntheticClient::import_find(const char *base, const char *find, bool data) } -int SyntheticClient::lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name) +int SyntheticClient::lookup_hash(inodeno_t ino, inodeno_t dirino, + const char *name, const UserPerm& perms) { - int r = client->lookup_hash(ino, dirino, name); + int r = client->lookup_hash(ino, dirino, name, perms); dout(0) << "lookup_hash(" << ino << ", #" << dirino << "/" << name << ") = " << r << dendl; return r; } -int SyntheticClient::lookup_ino(inodeno_t ino) +int SyntheticClient::lookup_ino(inodeno_t ino, const UserPerm& perms) { - int r = client->lookup_ino(ino); + int r = client->lookup_ino(ino, perms); dout(0) << "lookup_ino(" << ino << ") = " << r << dendl; return r; } int SyntheticClient::chunk_file(string &filename) { - int fd = client->open(filename.c_str(), O_RDONLY); + UserPerm perms = client->pick_my_perms(); + int fd = client->open(filename.c_str(), O_RDONLY, perms); if (fd < 0) return fd; struct stat st; - int ret = client->fstat(fd, &st); + int ret = client->fstat(fd, &st, perms); if (ret < 0) { client->close(fd); return ret; @@ -3388,23 +3422,24 @@ int SyntheticClient::chunk_file(string &filename) -void SyntheticClient::mksnap(const char *base, const char *name) +void SyntheticClient::mksnap(const char *base, const char *name, const UserPerm& perms) { - client->mksnap(base, name); + client->mksnap(base, name, perms); } -void SyntheticClient::rmsnap(const char *base, const char *name) +void SyntheticClient::rmsnap(const char *base, const char *name, const UserPerm& perms) { - client->rmsnap(base, name); + client->rmsnap(base, name, perms); } void SyntheticClient::mksnapfile(const char *dir) { - client->mkdir(dir, 0755); + UserPerm perms = client->pick_my_perms(); + client->mkdir(dir, 0755, perms); string f = dir; f += "/foo"; - int fd = client->open(f.c_str(), O_WRONLY|O_CREAT|O_TRUNC); + int fd = client->open(f.c_str(), O_WRONLY|O_CREAT|O_TRUNC, perms); char buf[1048576*4]; client->write(fd, buf, sizeof(buf), 0); @@ -3413,9 +3448,9 @@ void SyntheticClient::mksnapfile(const char *dir) string s = dir; s += "/.snap/1"; - client->mkdir(s.c_str(), 0755); + client->mkdir(s.c_str(), 0755, perms); - fd = client->open(f.c_str(), O_WRONLY); + fd = client->open(f.c_str(), O_WRONLY, perms); client->write(fd, buf, 1048576*2, 1048576); client->fsync(fd, true); client->close(fd); diff --git a/src/client/SyntheticClient.h b/src/client/SyntheticClient.h index e0687b403f490..755f5e0ef093f 100644 --- a/src/client/SyntheticClient.h +++ b/src/client/SyntheticClient.h @@ -265,13 +265,14 @@ class SyntheticClient { void import_find(const char *basedir, const char *find, bool writedata); - int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name); - int lookup_ino(inodeno_t ino); + int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name, + const UserPerm& perms); + int lookup_ino(inodeno_t ino, const UserPerm& perms); int chunk_file(string &filename); - void mksnap(const char *base, const char *name); - void rmsnap(const char *base, const char *name); + void mksnap(const char *base, const char *name, const UserPerm& perms); + void rmsnap(const char *base, const char *name, const UserPerm& perms); void mksnapfile(const char *dir); }; diff --git a/src/client/UserGroups.h b/src/client/UserGroups.h deleted file mode 100644 index 3a3966f2f8132..0000000000000 --- a/src/client/UserGroups.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CEPH_CLIENT_USERGROUPS_H -#define CEPH_CLIENT_USERGROUPS_H - -class UserGroups { -public: - virtual bool is_in(gid_t gid) = 0; - virtual gid_t get_gid() = 0; - virtual int get_gids(const gid_t **gids) = 0; - virtual ~UserGroups() {}; -}; - -#endif diff --git a/src/client/UserPerm.h b/src/client/UserPerm.h new file mode 100644 index 0000000000000..71775b00334e8 --- /dev/null +++ b/src/client/UserPerm.h @@ -0,0 +1,92 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2016 Red Hat + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#ifndef CEPH_CLIENT_USERPERM_H +#define CEPH_CLIENT_USERPERM_H + +struct UserPerm +{ +private: + uid_t m_uid; + gid_t m_gid; + int gid_count; + gid_t *gids; + bool alloced_gids; + void deep_copy_from(const UserPerm& b) { + if (alloced_gids) { + delete[] gids; + alloced_gids = false; + } + m_uid = b.m_uid; + m_gid = b.m_gid; + gid_count = b.gid_count; + if (gid_count) { + gids = new gid_t[gid_count]; + alloced_gids = true; + for (int i = 0; i < gid_count; ++i) { + gids[i] = b.gids[i]; + } + } + } +public: + UserPerm() : m_uid(-1), m_gid(-1), gid_count(0), + gids(NULL), alloced_gids(false) {} + UserPerm(int uid, int gid) : m_uid(uid), m_gid(gid), gid_count(0), + gids(NULL), alloced_gids(false) {} + UserPerm(const UserPerm& o) : UserPerm() { + deep_copy_from(o); + } + UserPerm(UserPerm && o) { + m_uid = o.m_uid; + m_gid = o.m_gid; + gid_count = o.gid_count; + gids = o.gids; + alloced_gids = o.alloced_gids; + o.gids = NULL; + o.gid_count = 0; + } + ~UserPerm() { + if (alloced_gids) + delete[] gids; + } + UserPerm& operator=(const UserPerm o) { + deep_copy_from(o); + return *this; + } + + uid_t uid() const { return m_uid; } + gid_t gid() const { return m_gid; } + bool gid_in_groups(gid_t gid) const { + if (gid == m_gid) return true; + for (int i = 0; i < gid_count; ++i) { + if (gid == gids[i]) return true; + } + return false; + } + int get_gids(const gid_t **_gids) const { *_gids = gids; return gid_count; } + void init_gids(gid_t* _gids, int count) { + gids = _gids; + gid_count = count; + } + void take_gids() { alloced_gids = true; } + void shallow_copy(const UserPerm& o) { + m_uid = o.m_uid; + m_gid = o.m_gid; + gid_count = o.gid_count; + gids = o.gids; + alloced_gids = false; + } +}; + +#endif diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index 1d4719ba30d6e..16089a2ea9929 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -97,6 +97,48 @@ class CephFuse::Handle { struct fuse_args args; }; +static int getgroups(fuse_req_t req, gid_t **sgids) +{ +#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) + assert(sgids); + int c = fuse_req_getgroups(req, 0, NULL); + if (c < 0) { + return c; + } + if (c == 0) { + return 0; + } + + *sgids = (gid_t*)malloc(c*sizeof(**sgids)); + if (!*sgids) { + return -ENOMEM; + } + c = fuse_req_getgroups(req, c, *sgids); + if (c < 0) { + free(*sgids); + return c; + } + return c; +#endif + return -ENOSYS; +} + +static int getgroups_cb(void *handle, gid_t **sgids) +{ + CephFuse::Handle *cfuse = (CephFuse::Handle *) handle; + fuse_req_t req = cfuse->get_fuse_req(); + return getgroups(req, sgids); +} + +#define GET_GROUPS(perms, req) { \ + if (cfuse->client->cct->_conf->fuse_set_user_groups) { \ + gid_t *gids = NULL; \ + int count = getgroups(req, &gids); \ + perms.init_gids(gids, count); \ + perms.take_gids(); \ + } } + + static CephFuse::Handle *fuse_ll_req_prepare(fuse_req_t req) { CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); @@ -111,9 +153,11 @@ static void fuse_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) struct fuse_entry_param fe; Inode *i2, *i1 = cfuse->iget(parent); // see below int r; + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); memset(&fe, 0, sizeof(fe)); - r = cfuse->client->ll_lookup(i1, name, &fe.attr, &i2, ctx->uid, ctx->gid); + r = cfuse->client->ll_lookup(i1, name, &fe.attr, &i2, perms); if (r >= 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); @@ -142,10 +186,12 @@ static void fuse_ll_getattr(fuse_req_t req, fuse_ino_t ino, const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); struct stat stbuf; + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); (void) fi; // XXX - if (cfuse->client->ll_getattr(in, &stbuf, ctx->uid, ctx->gid) + if (cfuse->client->ll_getattr(in, &stbuf, perms) == 0) { stbuf.st_ino = cfuse->make_fake_ino(stbuf.st_ino, stbuf.st_dev); stbuf.st_rdev = new_encode_dev(stbuf.st_rdev); @@ -162,6 +208,8 @@ static void fuse_ll_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, CephFuse::Handle *cfuse = fuse_ll_req_prepare(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); int mask = 0; if (to_set & FUSE_SET_ATTR_MODE) mask |= CEPH_SETATTR_MODE; @@ -175,7 +223,7 @@ static void fuse_ll_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, if (to_set & FUSE_SET_ATTR_ATIME_NOW) mask |= CEPH_SETATTR_ATIME_NOW; #endif - int r = cfuse->client->ll_setattr(in, attr, mask, ctx->uid, ctx->gid); + int r = cfuse->client->ll_setattr(in, attr, mask, perms); if (r == 0) fuse_reply_attr(req, attr, 0); else @@ -197,9 +245,10 @@ static void fuse_ll_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, CephFuse::Handle *cfuse = fuse_ll_req_prepare(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); - int r = cfuse->client->ll_setxattr(in, name, value, size, flags, ctx->uid, - ctx->gid); + int r = cfuse->client->ll_setxattr(in, name, value, size, flags, perms); fuse_reply_err(req, -r); cfuse->iput(in); // iput required @@ -211,8 +260,10 @@ static void fuse_ll_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); char buf[size]; + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); - int r = cfuse->client->ll_listxattr(in, buf, size, ctx->uid, ctx->gid); + int r = cfuse->client->ll_listxattr(in, buf, size, perms); if (size == 0 && r >= 0) fuse_reply_xattr(req, r); else if (r >= 0) @@ -234,8 +285,10 @@ static void fuse_ll_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); char buf[size]; + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); - int r = cfuse->client->ll_getxattr(in, name, buf, size, ctx->uid, ctx->gid); + int r = cfuse->client->ll_getxattr(in, name, buf, size, perms); if (size == 0 && r >= 0) fuse_reply_xattr(req, r); else if (r >= 0) @@ -252,9 +305,10 @@ static void fuse_ll_removexattr(fuse_req_t req, fuse_ino_t ino, CephFuse::Handle *cfuse = fuse_ll_req_prepare(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); - int r = cfuse->client->ll_removexattr(in, name, ctx->uid, - ctx->gid); + int r = cfuse->client->ll_removexattr(in, name, perms); fuse_reply_err(req, -r); cfuse->iput(in); // iput required @@ -268,8 +322,11 @@ static void fuse_ll_opendir(fuse_req_t req, fuse_ino_t ino, Inode *in = cfuse->iget(ino); void *dirp; + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); + int r = cfuse->client->ll_opendir(in, fi->flags, (dir_result_t **)&dirp, - ctx->uid, ctx->gid); + perms); if (r >= 0) { fi->fh = (uint64_t)dirp; fuse_reply_open(req, fi); @@ -286,8 +343,10 @@ static void fuse_ll_readlink(fuse_req_t req, fuse_ino_t ino) const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); char buf[PATH_MAX + 1]; // leave room for a null terminator + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); - int r = cfuse->client->ll_readlink(in, buf, sizeof(buf) - 1, ctx->uid, ctx->gid); + int r = cfuse->client->ll_readlink(in, buf, sizeof(buf) - 1, perms); if (r >= 0) { buf[r] = '\0'; fuse_reply_readlink(req, buf); @@ -305,11 +364,13 @@ static void fuse_ll_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *i2, *i1 = cfuse->iget(parent); struct fuse_entry_param fe; + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); memset(&fe, 0, sizeof(fe)); int r = cfuse->client->ll_mknod(i1, name, mode, new_decode_dev(rdev), - &fe.attr, &i2, ctx->uid, ctx->gid); + &fe.attr, &i2, perms); if (r == 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); @@ -332,7 +393,8 @@ static void fuse_ll_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, struct fuse_entry_param fe; memset(&fe, 0, sizeof(fe)); - + UserPerm perm(ctx->uid, ctx->gid); + GET_GROUPS(perm, req); #ifdef HAVE_SYS_SYNCFS if (cfuse->fino_snap(parent) == CEPH_SNAPDIR && cfuse->client->cct->_conf->fuse_multithreaded && @@ -355,8 +417,7 @@ static void fuse_ll_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, #endif i1 = cfuse->iget(parent); - int r = cfuse->client->ll_mkdir(i1, name, mode, &fe.attr, &i2, ctx->uid, - ctx->gid); + int r = cfuse->client->ll_mkdir(i1, name, mode, &fe.attr, &i2, perm); if (r == 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); @@ -375,8 +436,10 @@ static void fuse_ll_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) CephFuse::Handle *cfuse = fuse_ll_req_prepare(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(parent); + UserPerm perm(ctx->uid, ctx->gid); + GET_GROUPS(perm, req); - int r = cfuse->client->ll_unlink(in, name, ctx->uid, ctx->gid); + int r = cfuse->client->ll_unlink(in, name, perm); fuse_reply_err(req, -r); cfuse->iput(in); // iput required @@ -387,8 +450,10 @@ static void fuse_ll_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) CephFuse::Handle *cfuse = fuse_ll_req_prepare(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(parent); + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); - int r = cfuse->client->ll_rmdir(in, name, ctx->uid, ctx->gid); + int r = cfuse->client->ll_rmdir(in, name, perms); fuse_reply_err(req, -r); cfuse->iput(in); // iput required @@ -401,11 +466,12 @@ static void fuse_ll_symlink(fuse_req_t req, const char *existing, const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *i2, *i1 = cfuse->iget(parent); struct fuse_entry_param fe; + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); memset(&fe, 0, sizeof(fe)); - int r = cfuse->client->ll_symlink(i1, name, existing, &fe.attr, &i2, ctx->uid, - ctx->gid); + int r = cfuse->client->ll_symlink(i1, name, existing, &fe.attr, &i2, perms); if (r == 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); @@ -426,8 +492,10 @@ static void fuse_ll_rename(fuse_req_t req, fuse_ino_t parent, const char *name, const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(parent); Inode *nin = cfuse->iget(newparent); + UserPerm perm(ctx->uid, ctx->gid); + GET_GROUPS(perm, req); - int r = cfuse->client->ll_rename(in, name, nin, newname, ctx->uid, ctx->gid); + int r = cfuse->client->ll_rename(in, name, nin, newname, perm); fuse_reply_err(req, -r); cfuse->iput(in); // iputs required @@ -444,9 +512,10 @@ static void fuse_ll_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, struct fuse_entry_param fe; memset(&fe, 0, sizeof(fe)); + UserPerm perm(ctx->uid, ctx->gid); + GET_GROUPS(perm, req); - int r = cfuse->client->ll_link(in, nin, newname, &fe.attr, ctx->uid, - ctx->gid); + int r = cfuse->client->ll_link(in, nin, newname, &fe.attr, perm); if (r == 0) { fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); fe.attr.st_rdev = new_encode_dev(fe.attr.st_rdev); @@ -466,8 +535,10 @@ static void fuse_ll_open(fuse_req_t req, fuse_ino_t ino, const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); Fh *fh = NULL; + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); - int r = cfuse->client->ll_open(in, fi->flags, &fh, ctx->uid, ctx->gid); + int r = cfuse->client->ll_open(in, fi->flags, &fh, perms); if (r == 0) { fi->fh = (uint64_t)fh; #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) @@ -665,13 +736,15 @@ static void fuse_ll_create(fuse_req_t req, fuse_ino_t parent, const char *name, const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *i1 = cfuse->iget(parent), *i2; struct fuse_entry_param fe; - Fh *fh; + Fh *fh = NULL; + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); memset(&fe, 0, sizeof(fe)); // pass &i2 for the created inode so that ll_create takes an initial ll_ref int r = cfuse->client->ll_create(i1, name, mode, fi->flags, &fe.attr, &i2, - &fh, ctx->uid, ctx->gid); + &fh, perms); if (r == 0) { fi->fh = (uint64_t)fh; fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev); @@ -694,8 +767,11 @@ static void fuse_ll_statfs(fuse_req_t req, fuse_ino_t ino) struct statvfs stbuf; CephFuse::Handle *cfuse = fuse_ll_req_prepare(req); Inode *in = cfuse->iget(ino); + const struct fuse_ctx *ctx = fuse_req_ctx(req); + UserPerm perms(ctx->uid, ctx->gid); + GET_GROUPS(perms, req); - int r = cfuse->client->ll_statfs(in, &stbuf); + int r = cfuse->client->ll_statfs(in, &stbuf, perms); if (r == 0) fuse_reply_statfs(req, &stbuf); else @@ -770,36 +846,6 @@ static void fuse_ll_flock(fuse_req_t req, fuse_ino_t ino, } #endif -static int getgroups_cb(void *handle, gid_t **sgids) -{ -#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) - CephFuse::Handle *cfuse = (CephFuse::Handle *)handle; - fuse_req_t req = cfuse->get_fuse_req(); - - assert(sgids); - int c = fuse_req_getgroups(req, 0, NULL); - if (c < 0) { - return c; - } - if (c == 0) { - return 0; - } - - *sgids = (gid_t*)malloc(c*sizeof(**sgids)); - if (!*sgids) { - return -ENOMEM; - } - c = fuse_req_getgroups(req, c, *sgids); - if (c < 0) { - free(*sgids); - return c; - } - return c; -#else - return -ENOSYS; -#endif -} - #if !defined(DARWIN) static mode_t umask_cb(void *handle) { diff --git a/src/client/posix_acl.cc b/src/client/posix_acl.cc index d92d17a8f8582..e6331ed294c2c 100644 --- a/src/client/posix_acl.cc +++ b/src/client/posix_acl.cc @@ -1,7 +1,7 @@ #include "include/types.h" #include #include "posix_acl.h" -#include "UserGroups.h" +#include "UserPerm.h" #ifndef ACCESSPERMS #define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) @@ -220,7 +220,7 @@ int posix_acl_access_chmod(bufferptr& acl, mode_t mode) } int posix_acl_permits(const bufferptr& acl, uid_t i_uid, gid_t i_gid, - uid_t uid, UserGroups& groups, unsigned want) + const UserPerm& perms, unsigned want) { if (posix_acl_check(acl.c_str(), acl.length()) < 0) return -EIO; @@ -238,19 +238,19 @@ int posix_acl_permits(const bufferptr& acl, uid_t i_uid, gid_t i_gid, perm = entry->e_perm; switch(tag) { case ACL_USER_OBJ: - if (i_uid == uid) + if (i_uid == perms.uid()) goto check_perm; break; case ACL_USER: id = entry->e_id; - if (id == uid) + if (id == perms.uid()) goto check_mask; break; case ACL_GROUP_OBJ: /* fall through */ case ACL_GROUP: id = (tag == ACL_GROUP_OBJ) ? i_gid : entry->e_id; - if (groups.is_in(id)) { + if (perms.gid_in_groups(id)) { group_found = 1; if ((perm & want) == want) goto check_mask; diff --git a/src/client/posix_acl.h b/src/client/posix_acl.h index d9c5cc854bd90..4afcc3fe2e1e6 100644 --- a/src/client/posix_acl.h +++ b/src/client/posix_acl.h @@ -24,12 +24,12 @@ typedef struct { acl_ea_entry a_entries[0]; } acl_ea_header; -class UserGroups; +class UserPerm; int posix_acl_check(const void *xattr, size_t size); int posix_acl_equiv_mode(const void *xattr, size_t size, mode_t *mode_p); int posix_acl_inherit_mode(bufferptr& acl, mode_t *mode_p); int posix_acl_access_chmod(bufferptr& acl, mode_t mode); int posix_acl_permits(const bufferptr& acl, uid_t i_uid, gid_t i_gid, - uid_t uid, UserGroups& groups, unsigned want); + const UserPerm& groups, unsigned want); #endif diff --git a/src/common/config_opts.h b/src/common/config_opts.h index e3b7500850d23..3e2aa75ce1cbc 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -414,6 +414,7 @@ OPTION(fuse_debug, OPT_BOOL, false) OPTION(fuse_multithreaded, OPT_BOOL, true) OPTION(fuse_require_active_mds, OPT_BOOL, true) // if ceph_fuse requires active mds server OPTION(fuse_syncfs_on_mksnap, OPT_BOOL, true) +OPTION(fuse_set_user_groups, OPT_BOOL, false) // if ceph_fuse fills in group lists or not OPTION(client_try_dentry_invalidate, OPT_BOOL, true) // the client should try to use dentry invaldation instead of remounting, on kernels it believes that will work for OPTION(client_die_on_failed_remount, OPT_BOOL, true) diff --git a/src/libcephfs.cc b/src/libcephfs.cc index 9e65bff95d298..f24ff945fe4df 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -38,7 +38,8 @@ struct ceph_mount_info { public: explicit ceph_mount_info(CephContext *cct_) - : mounted(false), + : default_perms(), + mounted(false), inited(false), client(NULL), monclient(NULL), @@ -95,6 +96,7 @@ struct ceph_mount_info if (ret) goto fail; + default_perms = Client::pick_my_perms(cct); inited = true; return 0; @@ -103,7 +105,7 @@ struct ceph_mount_info return ret; } - int mount(const std::string &mount_root) + int mount(const std::string &mount_root, const UserPerm& perms) { int ret; @@ -117,7 +119,7 @@ struct ceph_mount_info } } - ret = client->mount(mount_root); + ret = client->mount(mount_root, perms); if (ret) { shutdown(); return ret; @@ -225,21 +227,22 @@ struct ceph_mount_info return client; } - const char *get_cwd() + const char *get_cwd(const UserPerm& perms) { - client->getcwd(cwd); + client->getcwd(cwd, perms); return cwd.c_str(); } - int chdir(const char *to) + int chdir(const char *to, const UserPerm& perms) { - return client->chdir(to, cwd); + return client->chdir(to, cwd, perms); } CephContext *get_ceph_context() const { return cct; } + UserPerm default_perms; private: bool mounted; bool inited; @@ -427,7 +430,7 @@ extern "C" int ceph_mount(struct ceph_mount_info *cmount, const char *root) std::string mount_root; if (root) mount_root = root; - return cmount->mount(mount_root); + return cmount->mount(mount_root, cmount->default_perms); } extern "C" int ceph_is_mounted(struct ceph_mount_info *cmount) @@ -440,7 +443,7 @@ extern "C" int ceph_statfs(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->statfs(path, stbuf); + return cmount->get_client()->statfs(path, stbuf, cmount->default_perms); } extern "C" int ceph_get_local_osd(struct ceph_mount_info *cmount) @@ -452,14 +455,14 @@ extern "C" int ceph_get_local_osd(struct ceph_mount_info *cmount) extern "C" const char* ceph_getcwd(struct ceph_mount_info *cmount) { - return cmount->get_cwd(); + return cmount->get_cwd(cmount->default_perms); } extern "C" int ceph_chdir (struct ceph_mount_info *cmount, const char *s) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->chdir(s); + return cmount->chdir(s, cmount->default_perms); } extern "C" int ceph_opendir(struct ceph_mount_info *cmount, @@ -467,7 +470,7 @@ extern "C" int ceph_opendir(struct ceph_mount_info *cmount, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->opendir(name, (dir_result_t **)dirpp); + return cmount->get_client()->opendir(name, (dir_result_t **)dirpp, cmount->default_perms); } extern "C" int ceph_closedir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp) @@ -544,14 +547,14 @@ extern "C" int ceph_link (struct ceph_mount_info *cmount, const char *existing, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->link(existing, newname); + return cmount->get_client()->link(existing, newname, cmount->default_perms); } extern "C" int ceph_unlink(struct ceph_mount_info *cmount, const char *path) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->unlink(path); + return cmount->get_client()->unlink(path, cmount->default_perms); } extern "C" int ceph_rename(struct ceph_mount_info *cmount, const char *from, @@ -559,7 +562,7 @@ extern "C" int ceph_rename(struct ceph_mount_info *cmount, const char *from, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->rename(from, to); + return cmount->get_client()->rename(from, to, cmount->default_perms); } // dirs @@ -567,21 +570,21 @@ extern "C" int ceph_mkdir(struct ceph_mount_info *cmount, const char *path, mode { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->mkdir(path, mode); + return cmount->get_client()->mkdir(path, mode, cmount->default_perms); } extern "C" int ceph_mkdirs(struct ceph_mount_info *cmount, const char *path, mode_t mode) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->mkdirs(path, mode); + return cmount->get_client()->mkdirs(path, mode, cmount->default_perms); } extern "C" int ceph_rmdir(struct ceph_mount_info *cmount, const char *path) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->rmdir(path); + return cmount->get_client()->rmdir(path, cmount->default_perms); } // symlinks @@ -590,7 +593,7 @@ extern "C" int ceph_readlink(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->readlink(path, buf, size); + return cmount->get_client()->readlink(path, buf, size, cmount->default_perms); } extern "C" int ceph_symlink(struct ceph_mount_info *cmount, const char *existing, @@ -598,7 +601,7 @@ extern "C" int ceph_symlink(struct ceph_mount_info *cmount, const char *existing { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->symlink(existing, newname); + return cmount->get_client()->symlink(existing, newname, cmount->default_perms); } // inode stuff @@ -607,7 +610,7 @@ extern "C" int ceph_stat(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->stat(path, stbuf); + return cmount->get_client()->stat(path, stbuf, cmount->default_perms); } extern "C" int ceph_statx(struct ceph_mount_info *cmount, const char *path, @@ -615,7 +618,8 @@ extern "C" int ceph_statx(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->statx(path, stx, want, flags); + return cmount->get_client()->statx(path, stx, cmount->default_perms, + want, flags); } extern "C" int ceph_lstat(struct ceph_mount_info *cmount, const char *path, @@ -623,7 +627,7 @@ extern "C" int ceph_lstat(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->lstat(path, stbuf); + return cmount->get_client()->lstat(path, stbuf, cmount->default_perms); } extern "C" int ceph_setattr(struct ceph_mount_info *cmount, const char *relpath, @@ -631,7 +635,7 @@ extern "C" int ceph_setattr(struct ceph_mount_info *cmount, const char *relpath, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->setattr(relpath, attr, mask); + return cmount->get_client()->setattr(relpath, attr, mask, cmount->default_perms); } extern "C" int ceph_setattrx(struct ceph_mount_info *cmount, const char *relpath, @@ -639,7 +643,8 @@ extern "C" int ceph_setattrx(struct ceph_mount_info *cmount, const char *relpath { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->setattrx(relpath, stx, mask, flags); + return cmount->get_client()->setattrx(relpath, stx, mask, + cmount->default_perms, flags); } // *xattr() calls supporting samba/vfs @@ -647,21 +652,22 @@ extern "C" int ceph_getxattr(struct ceph_mount_info *cmount, const char *path, c { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->getxattr(path, name, value, size); + + return cmount->get_client()->getxattr(path, name, value, size, cmount->default_perms); } extern "C" int ceph_lgetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->lgetxattr(path, name, value, size); + return cmount->get_client()->lgetxattr(path, name, value, size, cmount->default_perms); } extern "C" int ceph_fgetxattr(struct ceph_mount_info *cmount, int fd, const char *name, void *value, size_t size) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->fgetxattr(fd, name, value, size); + return cmount->get_client()->fgetxattr(fd, name, value, size, cmount->default_perms); } @@ -669,63 +675,63 @@ extern "C" int ceph_listxattr(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->listxattr(path, list, size); + return cmount->get_client()->listxattr(path, list, size, cmount->default_perms); } extern "C" int ceph_llistxattr(struct ceph_mount_info *cmount, const char *path, char *list, size_t size) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->llistxattr(path, list, size); + return cmount->get_client()->llistxattr(path, list, size, cmount->default_perms); } extern "C" int ceph_flistxattr(struct ceph_mount_info *cmount, int fd, char *list, size_t size) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->flistxattr(fd, list, size); + return cmount->get_client()->flistxattr(fd, list, size, cmount->default_perms); } extern "C" int ceph_removexattr(struct ceph_mount_info *cmount, const char *path, const char *name) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->removexattr(path, name); + return cmount->get_client()->removexattr(path, name, cmount->default_perms); } extern "C" int ceph_lremovexattr(struct ceph_mount_info *cmount, const char *path, const char *name) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->lremovexattr(path, name); + return cmount->get_client()->lremovexattr(path, name, cmount->default_perms); } extern "C" int ceph_fremovexattr(struct ceph_mount_info *cmount, int fd, const char *name) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->fremovexattr(fd, name); + return cmount->get_client()->fremovexattr(fd, name, cmount->default_perms); } extern "C" int ceph_setxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->setxattr(path, name, value, size, flags); + return cmount->get_client()->setxattr(path, name, value, size, flags, cmount->default_perms); } extern "C" int ceph_lsetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->lsetxattr(path, name, value, size, flags); + return cmount->get_client()->lsetxattr(path, name, value, size, flags, cmount->default_perms); } extern "C" int ceph_fsetxattr(struct ceph_mount_info *cmount, int fd, const char *name, const void *value, size_t size, int flags) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->fsetxattr(fd, name, value, size, flags); + return cmount->get_client()->fsetxattr(fd, name, value, size, flags, cmount->default_perms); } /* end xattr support */ @@ -733,34 +739,34 @@ extern "C" int ceph_chmod(struct ceph_mount_info *cmount, const char *path, mode { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->chmod(path, mode); + return cmount->get_client()->chmod(path, mode, cmount->default_perms); } extern "C" int ceph_fchmod(struct ceph_mount_info *cmount, int fd, mode_t mode) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->fchmod(fd, mode); + return cmount->get_client()->fchmod(fd, mode, cmount->default_perms); } extern "C" int ceph_chown(struct ceph_mount_info *cmount, const char *path, int uid, int gid) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->chown(path, uid, gid); + return cmount->get_client()->chown(path, uid, gid, cmount->default_perms); } extern "C" int ceph_fchown(struct ceph_mount_info *cmount, int fd, int uid, int gid) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->fchown(fd, uid, gid); + return cmount->get_client()->fchown(fd, uid, gid, cmount->default_perms); } extern "C" int ceph_lchown(struct ceph_mount_info *cmount, const char *path, int uid, int gid) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->lchown(path, uid, gid); + return cmount->get_client()->lchown(path, uid, gid, cmount->default_perms); } @@ -769,7 +775,7 @@ extern "C" int ceph_utime(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->utime(path, buf); + return cmount->get_client()->utime(path, buf, cmount->default_perms); } extern "C" int ceph_flock(struct ceph_mount_info *cmount, int fd, int operation, @@ -785,7 +791,7 @@ extern "C" int ceph_truncate(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->truncate(path, size); + return cmount->get_client()->truncate(path, size, cmount->default_perms); } // file ops @@ -794,7 +800,7 @@ extern "C" int ceph_mknod(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->mknod(path, mode, rdev); + return cmount->get_client()->mknod(path, mode, cmount->default_perms, rdev); } extern "C" int ceph_open(struct ceph_mount_info *cmount, const char *path, @@ -802,7 +808,7 @@ extern "C" int ceph_open(struct ceph_mount_info *cmount, const char *path, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->open(path, flags, mode); + return cmount->get_client()->open(path, flags, cmount->default_perms, mode); } extern "C" int ceph_open_layout(struct ceph_mount_info *cmount, const char *path, int flags, @@ -810,8 +816,9 @@ extern "C" int ceph_open_layout(struct ceph_mount_info *cmount, const char *path { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->open(path, flags, mode, stripe_unit, - stripe_count, object_size, data_pool); + return cmount->get_client()->open(path, flags, cmount->default_perms, mode, + stripe_unit, stripe_count, + object_size, data_pool); } extern "C" int ceph_close(struct ceph_mount_info *cmount, int fd) @@ -826,7 +833,7 @@ extern "C" int64_t ceph_lseek(struct ceph_mount_info *cmount, int fd, { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->lseek(fd, offset, whence); + return cmount->get_client()->lseek(fd, offset, whence, cmount->default_perms); } extern "C" int ceph_read(struct ceph_mount_info *cmount, int fd, char *buf, @@ -865,7 +872,7 @@ extern "C" int ceph_ftruncate(struct ceph_mount_info *cmount, int fd, int64_t si { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->ftruncate(fd, size); + return cmount->get_client()->ftruncate(fd, size, cmount->default_perms); } extern "C" int ceph_fsync(struct ceph_mount_info *cmount, int fd, int syncdataonly) @@ -887,7 +894,7 @@ extern "C" int ceph_fstat(struct ceph_mount_info *cmount, int fd, struct stat *s { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->fstat(fd, stbuf); + return cmount->get_client()->fstat(fd, stbuf, cmount->default_perms); } extern "C" int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_statx *stx, @@ -895,7 +902,8 @@ extern "C" int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_s { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->fstatx(fd, stx, want, flags); + return cmount->get_client()->fstatx(fd, stx, cmount->default_perms, + want, flags); } extern "C" int ceph_sync_fs(struct ceph_mount_info *cmount) @@ -926,7 +934,7 @@ extern "C" int ceph_get_path_stripe_unit(struct ceph_mount_info *cmount, const c if (!cmount->is_mounted()) return -ENOTCONN; - r = cmount->get_client()->describe_layout(path, &l); + r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms); if (r < 0) return r; return l.stripe_unit; @@ -952,7 +960,7 @@ extern "C" int ceph_get_path_stripe_count(struct ceph_mount_info *cmount, const if (!cmount->is_mounted()) return -ENOTCONN; - r = cmount->get_client()->describe_layout(path, &l); + r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms); if (r < 0) return r; return l.stripe_count; @@ -978,7 +986,7 @@ extern "C" int ceph_get_path_object_size(struct ceph_mount_info *cmount, const c if (!cmount->is_mounted()) return -ENOTCONN; - r = cmount->get_client()->describe_layout(path, &l); + r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms); if (r < 0) return r; return l.object_size; @@ -1004,7 +1012,7 @@ extern "C" int ceph_get_path_pool(struct ceph_mount_info *cmount, const char *pa if (!cmount->is_mounted()) return -ENOTCONN; - r = cmount->get_client()->describe_layout(path, &l); + r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms); if (r < 0) return r; return l.pool_id; @@ -1049,7 +1057,7 @@ extern "C" int ceph_get_path_pool_name(struct ceph_mount_info *cmount, const cha if (!cmount->is_mounted()) return -ENOTCONN; - r = cmount->get_client()->describe_layout(path, &l); + r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms); if (r < 0) return r; string name = cmount->get_client()->get_pool_name(l.pool_id); @@ -1089,7 +1097,7 @@ extern "C" int ceph_get_path_layout(struct ceph_mount_info *cmount, const char * if (!cmount->is_mounted()) return -ENOTCONN; - r = cmount->get_client()->describe_layout(path, &l); + r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms); if (r < 0) return r; if (stripe_unit) @@ -1124,7 +1132,7 @@ extern "C" int ceph_get_path_replication(struct ceph_mount_info *cmount, const c if (!cmount->is_mounted()) return -ENOTCONN; - r = cmount->get_client()->describe_layout(path, &l); + r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms); if (r < 0) return r; int rep = cmount->get_client()->get_pool_replication(l.pool_id); @@ -1301,7 +1309,7 @@ extern "C" int ceph_debug_get_file_caps(struct ceph_mount_info *cmount, const ch { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->get_caps_issued(path); + return cmount->get_client()->get_caps_issued(path, cmount->default_perms); } extern "C" int ceph_get_stripe_unit_granularity(struct ceph_mount_info *cmount) @@ -1362,7 +1370,7 @@ extern "C" int ceph_ll_lookup_inode( struct inodeno_t ino, Inode **inode) { - int r = (cmount->get_client())->lookup_ino(ino, inode); + int r = (cmount->get_client())->lookup_ino(ino, cmount->default_perms, inode); if (r) { return r; } @@ -1372,7 +1380,7 @@ extern "C" int ceph_ll_lookup_inode( // Request the parent inode, so that we can look up the name Inode *parent; - r = (cmount->get_client())->lookup_parent(*inode, &parent); + r = (cmount->get_client())->lookup_parent(*inode, cmount->default_perms, &parent); if (r && r != -EINVAL) { // Unexpected error (cmount->get_client())->ll_forget(*inode, 1); @@ -1382,10 +1390,12 @@ extern "C" int ceph_ll_lookup_inode( // and don't try to look up the non-existent dentry. return 0; } + // FIXME: I don't think this works; lookup_parent() returns 0 if the parent + // is already in cache assert(parent != NULL); // Finally, get the name (dentry) of the requested inode - r = (cmount->get_client())->lookup_name(*inode, parent); + r = (cmount->get_client())->lookup_name(*inode, parent, cmount->default_perms); if (r) { // Unexpected error (cmount->get_client())->ll_forget(parent, 1); @@ -1402,7 +1412,8 @@ extern "C" int ceph_ll_lookup(class ceph_mount_info *cmount, struct stat *attr, Inode **out, int uid, int gid) { - return (cmount->get_client())->ll_lookup(parent, name, attr, out, uid, gid); + UserPerm perms(uid, gid); + return (cmount->get_client())->ll_lookup(parent, name, attr, out, perms); } extern "C" int ceph_ll_put(class ceph_mount_info *cmount, Inode *in) @@ -1420,14 +1431,15 @@ extern "C" int ceph_ll_walk(class ceph_mount_info *cmount, const char *name, struct Inode **i, struct stat *attr) { - return(cmount->get_client()->ll_walk(name, i, attr)); + return (cmount->get_client()->ll_walk(name, i, attr, cmount->default_perms)); } extern "C" int ceph_ll_getattr(class ceph_mount_info *cmount, Inode *in, struct stat *attr, int uid, int gid) { - return (cmount->get_client()->ll_getattr(in, attr, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_getattr(in, attr, perms)); } extern "C" int ceph_ll_getattrx(class ceph_mount_info *cmount, @@ -1435,27 +1447,31 @@ extern "C" int ceph_ll_getattrx(class ceph_mount_info *cmount, unsigned int want, unsigned int flags, int uid, int gid) { - return (cmount->get_client()->ll_getattrx(in, stx, want, flags, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_getattrx(in, stx, want, flags, perms)); } extern "C" int ceph_ll_setattr(class ceph_mount_info *cmount, Inode *in, struct stat *st, int mask, int uid, int gid) { - return (cmount->get_client()->ll_setattr(in, st, mask, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_setattr(in, st, mask, perms)); } extern "C" int ceph_ll_setattrx(class ceph_mount_info *cmount, Inode *in, struct ceph_statx *stx, int mask, int uid, int gid) { - return (cmount->get_client()->ll_setattrx(in, stx, mask, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_setattrx(in, stx, mask, perms)); } extern "C" int ceph_ll_open(class ceph_mount_info *cmount, Inode *in, int flags, Fh **fh, int uid, int gid) { - return (cmount->get_client()->ll_open(in, flags, fh, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_open(in, flags, fh, perms)); } extern "C" int ceph_ll_read(class ceph_mount_info *cmount, Fh* filehandle, @@ -1516,7 +1532,7 @@ extern "C" int ceph_ll_fsync(class ceph_mount_info *cmount, extern "C" off_t ceph_ll_lseek(class ceph_mount_info *cmount, Fh *fh, off_t offset, int whence) { - return (cmount->get_client()->ll_lseek(fh, offset, whence)); + return (cmount->get_client()->ll_lseek(fh, offset, whence, cmount->default_perms)); } extern "C" int ceph_ll_write(class ceph_mount_info *cmount, @@ -1550,8 +1566,9 @@ extern "C" int ceph_ll_create(class ceph_mount_info *cmount, mode_t mode, int flags, struct stat *attr, struct Inode **out, Fh **fhp, int uid, int gid) { + UserPerm perms(uid, gid); return (cmount->get_client())->ll_create(parent, name, mode, flags, - attr, out, fhp, uid, gid); + attr, out, fhp, perms); } extern "C" int ceph_ll_mknod(class ceph_mount_info *cmount, @@ -1559,8 +1576,9 @@ extern "C" int ceph_ll_mknod(class ceph_mount_info *cmount, mode_t mode, dev_t rdev, struct stat *attr, struct Inode **out, int uid, int gid) { + UserPerm perms(uid, gid); return (cmount->get_client())->ll_mknod(parent, name, mode, rdev, - attr, out, uid, gid); + attr, out, perms); } extern "C" int ceph_ll_mkdir(class ceph_mount_info *cmount, @@ -1568,8 +1586,8 @@ extern "C" int ceph_ll_mkdir(class ceph_mount_info *cmount, mode_t mode, struct stat *attr, Inode **out, int uid, int gid) { - return (cmount->get_client()->ll_mkdir(parent, name, mode, attr, out, uid, - gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_mkdir(parent, name, mode, attr, out, perms)); } extern "C" int ceph_ll_link(class ceph_mount_info *cmount, @@ -1577,8 +1595,8 @@ extern "C" int ceph_ll_link(class ceph_mount_info *cmount, const char *name, struct stat *attr, int uid, int gid) { - return (cmount->get_client()->ll_link(in, newparent, name, attr, uid, - gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_link(in, newparent, name, attr, perms)); } extern "C" int ceph_ll_truncate(class ceph_mount_info *cmount, @@ -1587,9 +1605,9 @@ extern "C" int ceph_ll_truncate(class ceph_mount_info *cmount, { struct stat st; st.st_size=length; + UserPerm perms(uid, gid); - return(cmount->get_client()->ll_setattr(in, &st, CEPH_SETATTR_SIZE, uid, - gid)); + return(cmount->get_client()->ll_setattr(in, &st, CEPH_SETATTR_SIZE, perms)); } extern "C" int ceph_ll_opendir(class ceph_mount_info *cmount, @@ -1597,8 +1615,9 @@ extern "C" int ceph_ll_opendir(class ceph_mount_info *cmount, struct ceph_dir_result **dirpp, int uid, int gid) { + UserPerm perms(uid, gid); return (cmount->get_client()->ll_opendir(in, O_RDONLY, (dir_result_t**) dirpp, - uid, gid)); + perms)); } extern "C" int ceph_ll_releasedir(class ceph_mount_info *cmount, @@ -1613,28 +1632,31 @@ extern "C" int ceph_ll_rename(class ceph_mount_info *cmount, Inode *newparent, const char *newname, int uid, int gid) { - return (cmount->get_client()->ll_rename(parent, name, newparent, newname, - uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_rename(parent, name, + newparent, newname, perms)); } extern "C" int ceph_ll_unlink(class ceph_mount_info *cmount, Inode *in, const char *name, int uid, int gid) { - return (cmount->get_client()->ll_unlink(in, name, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_unlink(in, name, perms)); } extern "C" int ceph_ll_statfs(class ceph_mount_info *cmount, Inode *in, struct statvfs *stbuf) { - return (cmount->get_client()->ll_statfs(in, stbuf)); + return (cmount->get_client()->ll_statfs(in, stbuf, cmount->default_perms)); } extern "C" int ceph_ll_readlink(class ceph_mount_info *cmount, Inode *in, char *buf, size_t bufsiz, int uid, int gid) { - return (cmount->get_client()->ll_readlink(in, buf, bufsiz, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_readlink(in, buf, bufsiz, perms)); } extern "C" int ceph_ll_symlink(class ceph_mount_info *cmount, @@ -1642,28 +1664,31 @@ extern "C" int ceph_ll_symlink(class ceph_mount_info *cmount, const char *value, struct stat *attr, Inode **out, int uid, int gid) { - return (cmount->get_client()->ll_symlink(in, name, value, attr, out, uid, - gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_symlink(in, name, value, attr, out, perms)); } extern "C" int ceph_ll_rmdir(class ceph_mount_info *cmount, Inode *in, const char *name, int uid, int gid) { - return (cmount->get_client()->ll_rmdir(in, name, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_rmdir(in, name, perms)); } extern "C" int ceph_ll_getxattr(class ceph_mount_info *cmount, Inode *in, const char *name, void *value, size_t size, int uid, int gid) { - return (cmount->get_client()->ll_getxattr(in, name, value, size, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_getxattr(in, name, value, size, perms)); } extern "C" int ceph_ll_listxattr(struct ceph_mount_info *cmount, Inode *in, char *list, size_t buf_size, size_t *list_size, int uid, int gid) { - int res = cmount->get_client()->ll_listxattr(in, list, buf_size, uid, gid); + UserPerm perms(uid, gid); + int res = cmount->get_client()->ll_listxattr(in, list, buf_size, perms); if (res >= 0) { *list_size = (size_t)res; return 0; @@ -1676,15 +1701,16 @@ extern "C" int ceph_ll_setxattr(class ceph_mount_info *cmount, const void *value, size_t size, int flags, int uid, int gid) { - return (cmount->get_client()->ll_setxattr(in, name, value, size, flags, uid, - gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_setxattr(in, name, value, size, flags, perms)); } extern "C" int ceph_ll_removexattr(class ceph_mount_info *cmount, Inode *in, const char *name, int uid, int gid) { - return (cmount->get_client()->ll_removexattr(in, name, uid, gid)); + UserPerm perms(uid, gid); + return (cmount->get_client()->ll_removexattr(in, name, perms)); } extern "C" int ceph_ll_getlk(struct ceph_mount_info *cmount, diff --git a/src/mds/Locker.cc b/src/mds/Locker.cc index b65dd9f286dc4..d61c935a880be 100644 --- a/src/mds/Locker.cc +++ b/src/mds/Locker.cc @@ -3167,7 +3167,7 @@ bool Locker::_do_cap_update(CInode *in, Capability *cap, Session *session = static_cast(m->get_connection()->get_priv()); if (session->check_access(in, MAY_WRITE, - m->caller_uid, m->caller_gid, 0, 0) < 0) { + m->caller_uid, m->caller_gid, NULL, 0, 0) < 0) { session->put(); dout(10) << "check_access failed, dropping cap update on " << *in << dendl; return false; diff --git a/src/mds/MDSAuthCaps.cc b/src/mds/MDSAuthCaps.cc index c774d3f2473ea..0fc1dc09e6cea 100644 --- a/src/mds/MDSAuthCaps.cc +++ b/src/mds/MDSAuthCaps.cc @@ -110,12 +110,24 @@ void MDSCapMatch::normalize_path() bool MDSCapMatch::match(const std::string &target_path, const int caller_uid, - const int caller_gid) const + const int caller_gid, + const vector *caller_gid_list) const { if (uid != MDS_AUTH_UID_ANY) { if (uid != caller_uid) return false; - if (std::find(gids.begin(), gids.end(), caller_gid) == gids.end()) + bool gid_matched = false; + if (std::find(gids.begin(), gids.end(), caller_gid) != gids.end()) + gid_matched = true; + if (caller_gid_list) { + for (auto i = caller_gid_list->begin(); i != caller_gid_list->end(); ++i) { + if (std::find(gids.begin(), gids.end(), *i) != gids.end()) { + gid_matched = true; + break; + } + } + } + if (!gid_matched) return false; } @@ -168,6 +180,7 @@ bool MDSAuthCaps::is_capable(const std::string &inode_path, uid_t inode_uid, gid_t inode_gid, unsigned inode_mode, uid_t caller_uid, gid_t caller_gid, + const vector *caller_gid_list, unsigned mask, uid_t new_uid, gid_t new_gid) const { @@ -176,6 +189,7 @@ bool MDSAuthCaps::is_capable(const std::string &inode_path, << " owner " << inode_uid << ":" << inode_gid << " mode 0" << std::oct << inode_mode << std::dec << ") by caller " << caller_uid << ":" << caller_gid +// << "[" << caller_gid_list << "]"; << " mask " << mask << " new " << new_uid << ":" << new_gid << " cap: " << *this << dendl; @@ -184,8 +198,21 @@ bool MDSAuthCaps::is_capable(const std::string &inode_path, i != grants.end(); ++i) { - if (i->match.match(inode_path, caller_uid, caller_gid) && + if (i->match.match(inode_path, caller_uid, caller_gid, caller_gid_list) && i->spec.allows(mask & (MAY_READ|MAY_EXECUTE), mask & MAY_WRITE)) { + // we have a match; narrow down GIDs to those specifically allowed here + vector gids; + if (std::find(i->match.gids.begin(), i->match.gids.end(), caller_gid) != + i->match.gids.end()) { + gids.push_back(caller_gid); + } + if (caller_gid_list) { + std::set_intersection(i->match.gids.begin(), i->match.gids.end(), + caller_gid_list->begin(), caller_gid_list->end(), + std::back_inserter(gids)); + std::sort(gids.begin(), gids.end()); + } + // Spec is non-allowing if caller asked for set pool but spec forbids it if (mask & MAY_SET_POOL) { @@ -209,8 +236,8 @@ bool MDSAuthCaps::is_capable(const std::string &inode_path, if (mask & MAY_CHGRP) { // you can only chgrp *to* one of your groups... if you own the file. if (inode_uid != caller_uid || - std::find(i->match.gids.begin(), i->match.gids.end(), new_gid) == - i->match.gids.end()) { + std::find(gids.begin(), gids.end(), new_gid) == + gids.end()) { continue; } } @@ -221,8 +248,8 @@ bool MDSAuthCaps::is_capable(const std::string &inode_path, (!(mask & MAY_EXECUTE) || (inode_mode & S_IXUSR))) { return true; } - } else if (std::find(i->match.gids.begin(), i->match.gids.end(), - inode_gid) != i->match.gids.end()) { + } else if (std::find(gids.begin(), gids.end(), + inode_gid) != gids.end()) { if ((!(mask & MAY_READ) || (inode_mode & S_IRGRP)) && (!(mask & MAY_WRITE) || (inode_mode & S_IWGRP)) && (!(mask & MAY_EXECUTE) || (inode_mode & S_IXGRP))) { @@ -265,6 +292,9 @@ bool MDSAuthCaps::parse(CephContext *c, const std::string& str, ostream *err) bool r = qi::phrase_parse(iter, end, g, ascii::space, *this); cct = c; // set after parser self-assignment if (r && iter == end) { + for (auto& grant : grants) { + std::sort(grant.match.gids.begin(), grant.match.gids.end()); + } return true; } else { // Make sure no grants are kept after parsing failed! diff --git a/src/mds/MDSAuthCaps.h b/src/mds/MDSAuthCaps.h index eee7707fe03cc..19a62a6c93630 100644 --- a/src/mds/MDSAuthCaps.h +++ b/src/mds/MDSAuthCaps.h @@ -93,7 +93,8 @@ struct MDSCapMatch { // check whether this grant matches against a given file and caller uid:gid bool match(const std::string &target_path, const int caller_uid, - const int caller_gid) const; + const int caller_gid, + const vector *caller_gid_list) const; /** * Check whether this path *might* be accessible (actual permission @@ -132,8 +133,8 @@ class MDSAuthCaps bool allow_all() const; bool is_capable(const std::string &inode_path, uid_t inode_uid, gid_t inode_gid, unsigned inode_mode, - uid_t uid, gid_t gid, unsigned mask, - uid_t new_uid, gid_t new_gid) const; + uid_t uid, gid_t gid, const vector *caller_gid_list, + unsigned mask, uid_t new_uid, gid_t new_gid) const; bool path_capable(const std::string &inode_path) const; friend std::ostream &operator<<(std::ostream &out, const MDSAuthCaps &cap); diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 9a6bc92c05d63..0fea94f0891d0 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -2147,6 +2147,7 @@ bool Server::check_access(MDRequestRef& mdr, CInode *in, unsigned mask) in, mask, mdr->client_request->get_caller_uid(), mdr->client_request->get_caller_gid(), + &mdr->client_request->get_caller_gid_list(), mdr->client_request->head.args.setattr.uid, mdr->client_request->head.args.setattr.gid); if (r < 0) { diff --git a/src/mds/SessionMap.cc b/src/mds/SessionMap.cc index 9c536e1a020c7..efe43f5d11338 100644 --- a/src/mds/SessionMap.cc +++ b/src/mds/SessionMap.cc @@ -862,6 +862,7 @@ void Session::decode(bufferlist::iterator &p) int Session::check_access(CInode *in, unsigned mask, int caller_uid, int caller_gid, + const vector *caller_gid_list, int new_uid, int new_gid) { string path; @@ -887,7 +888,7 @@ int Session::check_access(CInode *in, unsigned mask, } if (!auth_caps.is_capable(path, in->inode.uid, in->inode.gid, in->inode.mode, - caller_uid, caller_gid, mask, + caller_uid, caller_gid, caller_gid_list, mask, new_uid, new_gid)) { return -EACCES; } diff --git a/src/mds/SessionMap.h b/src/mds/SessionMap.h index ec28e4483bf9e..f3de92ab79d69 100644 --- a/src/mds/SessionMap.h +++ b/src/mds/SessionMap.h @@ -312,7 +312,7 @@ class Session : public RefCountedObject { } int check_access(CInode *in, unsigned mask, int caller_uid, int caller_gid, - int new_uid, int new_gid); + const vector *gid_list, int new_uid, int new_gid); Session() : diff --git a/src/messages/MClientRequest.h b/src/messages/MClientRequest.h index 543761ec473d0..2fba0ca6d15aa 100644 --- a/src/messages/MClientRequest.h +++ b/src/messages/MClientRequest.h @@ -76,6 +76,7 @@ class MClientRequest : public Message { // path arguments filepath path, path2; + vector gid_list; @@ -137,6 +138,12 @@ class MClientRequest : public Message { void set_string2(const char *s) { path2.set_path(s, 0); } void set_caller_uid(unsigned u) { head.caller_uid = u; } void set_caller_gid(unsigned g) { head.caller_gid = g; } + void set_gid_list(int count, const gid_t *gids) { + gid_list.reserve(count); + for (int i = 0; i < count; ++i) { + gid_list.push_back(gids[i]); + } + } void set_dentry_wanted() { head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY; } @@ -151,6 +158,7 @@ class MClientRequest : public Message { int get_op() const { return head.op; } unsigned get_caller_uid() const { return head.caller_uid; } unsigned get_caller_gid() const { return head.caller_gid; } + const vector& get_caller_gid_list() const { return gid_list; } const string& get_path() const { return path.get_path(); } const filepath& get_filepath() const { return path; } @@ -187,6 +195,8 @@ class MClientRequest : public Message { ::decode_nohead(head.num_releases, releases, p); if (header.version >= 2) ::decode(stamp, p); + if (header.version >= 4) // epoch 3 was for a ceph_mds_request_args change + ::decode(gid_list, p); } void encode_payload(uint64_t features) { @@ -206,6 +216,7 @@ class MClientRequest : public Message { ::encode(path2, payload); ::encode_nohead(releases, payload); ::encode(stamp, payload); + ::encode(gid_list, payload); } const char *get_type_name() const { return "creq"; } @@ -249,7 +260,13 @@ class MClientRequest : public Message { out << " RETRY=" << (int)head.num_retry; if (get_flags() & CEPH_MDS_FLAG_REPLAY) out << " REPLAY"; - out << ")"; + out << " caller_uid=" << head.caller_uid + << ", caller_gid=" << head.caller_gid + << '{'; + for (auto i = gid_list.begin(); i != gid_list.end(); ++i) + out << *i << ','; + out << '}' + << ")"; } }; diff --git a/src/test/libcephfs/access.cc b/src/test/libcephfs/access.cc index 7574d2599d5a0..ebdf499aaabb0 100644 --- a/src/test/libcephfs/access.cc +++ b/src/test/libcephfs/access.cc @@ -308,9 +308,10 @@ TEST(AccessTest, User) { // chown and chgrp ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0700)); ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 456)); - ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 789)); + // FIXME: Re-enable these 789 tests once we can set multiple GIDs via libcephfs/config + // ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 789)); ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 456)); - ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 789)); + // ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 789)); ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 456)); ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, 1)); ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 1, 456)); @@ -327,7 +328,7 @@ TEST(AccessTest, User) { ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 1)); ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 456)); - ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 789)); + // ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 789)); ceph_shutdown(cmount); diff --git a/src/test/mds/TestMDSAuthCaps.cc b/src/test/mds/TestMDSAuthCaps.cc index 919095d9d2fb9..eb2cb43bd7c11 100644 --- a/src/test/mds/TestMDSAuthCaps.cc +++ b/src/test/mds/TestMDSAuthCaps.cc @@ -114,84 +114,97 @@ TEST(MDSAuthCaps, AllowAll) { ASSERT_TRUE(cap.parse(g_ceph_context, "allow *", NULL)); ASSERT_TRUE(cap.allow_all()); - ASSERT_TRUE(cap.is_capable("foo/bar", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo/bar", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); } TEST(MDSAuthCaps, AllowUid) { MDSAuthCaps cap(g_ceph_context); - ASSERT_TRUE(cap.parse(g_ceph_context, "allow * uid=10 gids=10,11; allow * uid=12 gids=12", NULL)); + ASSERT_TRUE(cap.parse(g_ceph_context, "allow * uid=10 gids=10,11,12; allow * uid=12 gids=12,10", NULL)); ASSERT_FALSE(cap.allow_all()); // uid/gid must be valid - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 0, 0, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 10, 0, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 9, 10, MAY_READ, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0777, 10, 10, MAY_READ, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0777, 12, 12, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 10, 12, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 0, 0, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 10, 0, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 9, 10, NULL, MAY_READ, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0777, 10, 10, NULL, MAY_READ, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0777, 12, 12, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 10, 13, NULL, MAY_READ, 0, 0)); // user - ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0500, 10, 11, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 10, 10, 0500, 10, 11, MAY_WRITE, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 10, 10, 0500, 10, 11, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0700, 10, 11, MAY_READ, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0700, 10, 11, MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0700, 10, 10, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 10, 0, 0700, 10, 10, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 12, 0, 0700, 10, 10, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 12, 0, 0700, 12, 12, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0700, 10, 10, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0500, 10, 11, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 10, 10, 0500, 10, 11, NULL, MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 10, 10, 0500, 10, 11, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0700, 10, 11, NULL, MAY_READ, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0700, 10, 11, NULL, MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0700, 10, 10, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 10, 0, 0700, 10, 10, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 12, 0, 0700, 10, 10, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 12, 0, 0700, 12, 12, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0700, 10, 10, NULL, MAY_READ | MAY_WRITE, 0, 0)); // group - ASSERT_TRUE(cap.is_capable("foo", 0, 10, 0750, 10, 10, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 10, 0750, 10, 10, MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 0, 10, 0770, 10, 10, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 0, 10, 0770, 10, 11, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 0, 11, 0770, 10, 10, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 0, 11, 0770, 10, 11, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 0, 12, 0770, 12, 12, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 10, 0770, 12, 12, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 12, 0770, 10, 10, MAY_READ | MAY_WRITE, 0, 0)); + vector glist10; + glist10.push_back(10); + vector dglist10; + dglist10.push_back(8); + dglist10.push_back(10); + vector glist11; + glist11.push_back(11); + vector glist12; + glist12.push_back(12); + ASSERT_TRUE(cap.is_capable("foo", 0, 10, 0750, 10, 10, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 10, 0750, 10, 10, NULL, MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 10, 0770, 10, 10, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 10, 0770, 10, 11, &glist10, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 11, 0770, 10, 10, &glist11, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 11, 0770, 10, 11, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 12, 0770, 12, 12, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 10, 0770, 12, 12, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 10, 0770, 12, 12, &glist10, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 10, 0770, 12, 12, &dglist10, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 11, 0770, 12, 12, &glist11, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 12, 0770, 10, 10, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 12, 0770, 10, 10, &glist12, MAY_READ | MAY_WRITE, 0, 0)); // user > group - ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0570, 10, 10, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 10, 10, 0570, 10, 10, MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 10, 10, 0570, 10, 10, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 10, 10, 0570, 10, 10, NULL, MAY_WRITE, 0, 0)); // other - ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0775, 10, 10, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0770, 10, 10, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0775, 10, 10, MAY_WRITE, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0775, 10, 10, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0777, 10, 10, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0773, 10, 10, MAY_READ, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0775, 10, 10, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0770, 10, 10, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0775, 10, 10, NULL, MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0775, 10, 10, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0777, 10, 10, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0773, 10, 10, NULL, MAY_READ, 0, 0)); // group > other - ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0557, 10, 10, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 10, 0557, 10, 10, MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0557, 10, 10, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 10, 0557, 10, 10, NULL, MAY_WRITE, 0, 0)); // user > other - ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0557, 10, 10, MAY_READ, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 10, 0, 0557, 10, 10, MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0557, 10, 10, NULL, MAY_READ, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 10, 0, 0557, 10, 10, NULL, MAY_WRITE, 0, 0)); } TEST(MDSAuthCaps, AllowPath) { MDSAuthCaps cap; ASSERT_TRUE(cap.parse(g_ceph_context, "allow * path=/sandbox", NULL)); ASSERT_FALSE(cap.allow_all()); - ASSERT_TRUE(cap.is_capable("sandbox/foo", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_TRUE(cap.is_capable("sandbox", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(cap.is_capable("sandboxed", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("sandbox/foo", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(cap.is_capable("sandbox", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("sandboxed", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); } TEST(MDSAuthCaps, AllowPathChars) { MDSAuthCaps unquo_cap; ASSERT_TRUE(unquo_cap.parse(g_ceph_context, "allow * path=/sandbox-._foo", NULL)); ASSERT_FALSE(unquo_cap.allow_all()); - ASSERT_TRUE(unquo_cap.is_capable("sandbox-._foo/foo", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(unquo_cap.is_capable("sandbox", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(unquo_cap.is_capable("sandbox-._food", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(unquo_cap.is_capable("foo", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(unquo_cap.is_capable("sandbox-._foo/foo", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(unquo_cap.is_capable("sandbox", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(unquo_cap.is_capable("sandbox-._food", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(unquo_cap.is_capable("foo", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); } @@ -199,10 +212,10 @@ TEST(MDSAuthCaps, AllowPathCharsQuoted) { MDSAuthCaps quo_cap; ASSERT_TRUE(quo_cap.parse(g_ceph_context, "allow * path=\"/sandbox-._foo\"", NULL)); ASSERT_FALSE(quo_cap.allow_all()); - ASSERT_TRUE(quo_cap.is_capable("sandbox-._foo/foo", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(quo_cap.is_capable("sandbox", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(quo_cap.is_capable("sandbox-._food", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); - ASSERT_FALSE(quo_cap.is_capable("foo", 0, 0, 0777, 0, 0, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_TRUE(quo_cap.is_capable("sandbox-._foo/foo", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(quo_cap.is_capable("sandbox", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(quo_cap.is_capable("sandbox-._food", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); + ASSERT_FALSE(quo_cap.is_capable("foo", 0, 0, 0777, 0, 0, NULL, MAY_READ | MAY_WRITE, 0, 0)); } TEST(MDSAuthCaps, OutputParsed) {