From: František Dvořák Date: Thu, 17 Oct 2013 19:55:24 +0000 (+0200) Subject: Implementation of setOwner() using xattrs. X-Git-Url: http://scientific.zcu.cz/git/?a=commitdiff_plain;h=e1b33095a6a6a8f55c1f5ee5521c5e8dfc543224;p=dmlite-plugins-vfs.git Implementation of setOwner() using xattrs. --- 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; + } + } }