From e1b33095a6a6a8f55c1f5ee5521c5e8dfc543224 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Thu, 17 Oct 2013 21:55:24 +0200 Subject: [PATCH] Implementation of setOwner() using xattrs. --- src/VfsNs.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/src/VfsNs.cpp b/src/VfsNs.cpp index fee71c8..bf15ee9 100644 --- a/src/VfsNs.cpp +++ b/src/VfsNs.cpp @@ -579,7 +579,73 @@ void VfsCatalog::setMode(const std::string& path, mode_t mode) throw (DmExceptio void VfsCatalog::setOwner(const std::string& path, uid_t newUid, gid_t newGid, bool followSymLink) throw (DmException) { - vfsThrow(ENOSYS, "changing owner not supported"); + ExtendedStat meta; + std::string lpath; + char buf[10]; + + if (vfsCheckPermissions(path, S_IWRITE)) + vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); + + meta = this->vfsExtendedStat(path); + + // If -1, no changes + if (newUid == (uid_t)-1) + newUid = meta.stat.st_uid; + if (newGid == (gid_t)-1) + newGid = meta.stat.st_gid; + + // Make sense to do anything? + if (newUid == meta.stat.st_uid && newGid == meta.stat.st_gid) + return; + + // If root, skip all checks + if (getUid(this->secCtx_) != 0) { + // Only root can change the owner + if (meta.stat.st_uid != newUid) + vfsThrow(EPERM, "'%s' not root user, setting owner on '%s' rejected", clientName.c_str(), path.c_str()); + + // If the group is changing... + if (meta.stat.st_gid != newGid) { + // The user has to be the owner + if (meta.stat.st_uid != getUid(this->secCtx_)) + vfsThrow(EPERM, "'%s' neither root nor owner, setting group on '%s' rejected", clientName.c_str(), path.c_str()); + // AND it has to belong to that group + if (!hasGroup(this->secCtx_->groups, newGid)) + vfsThrow(EPERM, "'%s' does not belong to group %d, setting group on '%s' rejected", clientName.c_str(), newGid, path.c_str()); + } + } + + lpath = getLocalPath(path); + + try { + if (newUid != meta.stat.st_uid) { + snprintf(buf, sizeof buf, "%u", newUid); + vfsSetXattr(path, lpath, VFS_XATTR "owner", buf, ATTR_DONTFOLLOW); + } + if (newGid != meta.stat.st_gid) { + snprintf(buf, sizeof buf, "%u", newGid); + vfsSetXattr(path, lpath, VFS_XATTR "group", buf, ATTR_DONTFOLLOW); + } + + // Update the ACL's if there is any + if (!meta.acl.empty()) { + for (size_t i = 0; i < meta.acl.size(); i++) { + if (meta.acl[i].type == AclEntry::kUserObj) + meta.acl[i].id = newUid; + else if (meta.acl[i].type == AclEntry::kGroupObj) + meta.acl[i].id = newGid; + } + vfsSetXattr(path, lpath, VFS_XATTR "acl", buf, ATTR_DONTFOLLOW); + } + } catch (DmException& e) { + // xattrs are not supported on symbolic links + // ==> ignore error for symlinks when followSymLink=false + if (!followSymLink && S_ISLNK(meta.stat.st_mode)) { + debug("ignored xattr errors on symbolic link '%s'", lpath.c_str()); + } else { + throw; + } + } } -- 1.8.2.3