From 6eabacad64e35a757251145a6a23904ca4ca55ee Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Thu, 17 Oct 2013 21:58:01 +0200 Subject: [PATCH] Fix setMode() vs VFS internal xattr: use separated "mode" attribute for the mode and always set read+write for the owner on filesystem. --- src/VfsNs.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/src/VfsNs.cpp b/src/VfsNs.cpp index 35a7867..bf0882e 100644 --- a/src/VfsNs.cpp +++ b/src/VfsNs.cpp @@ -160,12 +160,37 @@ std::string VfsCatalog::getWorkingDir(void) throw (DmException) /// attributes). /// void VfsCatalog::vfsUpdateStat(ExtendedStat &xStat, Extensible xattrs) throw (DmException) { + std::string modeStr; + mode_t mode; + char *parse; + if (xattrs.hasField(VFS_XATTR "acl")) xStat.acl = Acl(xattrs.getString(VFS_XATTR "acl")); else xStat.acl = Acl(); xStat.stat.st_gid = xattrs.getUnsigned(VFS_XATTR "group", VFS_GID_NONE); xStat.stat.st_uid = xattrs.getUnsigned(VFS_XATTR "owner", VFS_UID_NONE); + + modeStr = xattrs.getString(VFS_XATTR "mode", ""); + if (!modeStr.empty()) { + errno = 0; + mode = strtoull(modeStr.c_str(), &parse, 8); + if (*parse || errno) { +#ifdef DEBUG + // let's not throw up in ExtendedStat() + // ==> only debug + vfsThrowErrno("conversion of the mode '%s' failed on '%s'", modeStr.c_str(), xStat.name.c_str()); +#else + log(LOG_ERR, "conversion of the mode '%s' failed on '%s'", modeStr.c_str(), xStat.name.c_str()); +#endif + } else { + // prefer type from the filesystem + mode &= ~S_IFMT; + mode |= xStat.stat.st_mode & S_IFMT; + // use xattr for everything else + xStat.stat.st_mode = mode; + } + } } @@ -586,6 +611,7 @@ mode_t VfsCatalog::umask(mode_t mask) throw () void VfsCatalog::setMode(const std::string& path, mode_t mode) throw (DmException) { ExtendedStat meta; + char buf[20]; if (vfsCheckPermissions(path, S_IWRITE)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); @@ -597,14 +623,24 @@ void VfsCatalog::setMode(const std::string& path, mode_t mode) throw (DmExceptio getUid(this->secCtx_) != 0) { vfsThrow(EACCES, "'%s' neither owner nor root, setting the mode of '%s' rejected", clientName.c_str(), path.c_str()); } - // Clean up unwanted bits + + // Clean up unwanted bits (keep type, read/write for owner, correct sticky bit) mode &= ~S_IFMT; - // Keep type bits mode |= (meta.stat.st_mode & S_IFMT); - // TODO: buildin resets S_ISGID if not in the group - // TODO: update ACL (kUserObj, kGroupObj/kMask, kOther) + if (getUid(this->secCtx_) != 0 && + !hasGroup(this->secCtx_->groups, meta.stat.st_gid)) + mode &= ~S_ISGID; - wrapCall(chmod(getLocalPath(path).c_str(), mode)); + // + // Set the mode on the filesystem + // + // But keep read/write for owner. + // Filesystem mode couldn't be needed, but let's set it anyway. + // + wrapCall(chmod(getLocalPath(path).c_str(), mode | S_IRUSR | S_IWUSR)); + + snprintf(buf, sizeof buf, "%04o", mode); + vfsSetXattr(path, getLocalPath(path), VFS_XATTR "mode", buf, 0); } @@ -989,7 +1025,8 @@ ExtendedStat* VfsCatalog::readDirx(Directory* dir) throw (DmException) void VfsCatalog::makeDir(const std::string& path, mode_t mode) throw (DmException) { - std::string parentPath, name; + std::string lpath, parentPath, name; + char buf[20]; if (vfsCheckPermissions(path, S_IWRITE)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); @@ -1004,11 +1041,19 @@ void VfsCatalog::makeDir(const std::string& path, mode_t mode) throw (DmExceptio if (checkPermissions(this->secCtx_, parent.acl, parent.stat, S_IWRITE) != 0) vfsThrow(EACCES, "need write access for '%s' on '%s' to create directory '%s'", clientName.c_str(), parentPath.c_str(), name.c_str()); + lpath = getLocalPath(path); + // Clean up unwanted bits mode &= ~S_IFMT; + mode |= S_IFDIR; // TODO: S_ISGID // TODO: inherit default ACL - wrapCall(mkdir(getLocalPath(path).c_str(), mode)); + + // Keep read/write for owner in the mode + wrapCall(mkdir(lpath.c_str(), mode | S_IRUSR | S_IWUSR)); + + snprintf(buf, sizeof buf, "%04o", mode); + vfsSetXattr(path, lpath, VFS_XATTR "mode", buf, 0); } @@ -1271,6 +1316,7 @@ Extensible VfsCatalog::vfsGetXattrs(const std::string& path, const std::string& if (IS_VFS_XATTR(entry->a_name)) { if (strcmp(entry->a_name + VFS_XATTR_LENGTH, "acl") == 0 || strcmp(entry->a_name + VFS_XATTR_LENGTH, "group") == 0 || + strcmp(entry->a_name + VFS_XATTR_LENGTH, "mode") == 0 || strcmp(entry->a_name + VFS_XATTR_LENGTH, "owner") == 0) { attrType = VFS_XATTR_TYPE_PERMS; -- 1.8.2.3