From: František Dvořák Date: Sat, 19 Oct 2013 19:15:59 +0000 (+0200) Subject: Implement setAcl() using xatrs, update setMode(), setOwner() and create(). X-Git-Url: http://scientific.zcu.cz/git/?a=commitdiff_plain;h=06193129858f2129ad3ef7bc98167b04c8181895;p=dmlite-plugins-vfs.git Implement setAcl() using xatrs, update setMode(), setOwner() and create(). --- diff --git a/src/VfsNs.cpp b/src/VfsNs.cpp index aac7ead..6efe32f 100644 --- a/src/VfsNs.cpp +++ b/src/VfsNs.cpp @@ -543,6 +543,8 @@ void VfsCatalog::create(const std::string& path, mode_t mode) throw (DmException std::string parentPath, name, lpath; int code = DMLITE_SUCCESS; ExtendedStat file; + gid_t egid; + Acl newAcl; if (vfsCheckPermissions(path, S_IWRITE)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); @@ -564,25 +566,29 @@ void VfsCatalog::create(const std::string& path, mode_t mode) throw (DmException if (code != ENOENT) throw; } -#if 0 - // Effective gid - gid_t egid; - if (parent.stat.st_mode & S_ISGID) { - egid = parent.stat.st_gid; - mode |= S_ISGID; - } else { - egid = getGid(this->secCtx_); - } - // Generate inherited ACL's if there are defaults - if (parent.acl.has(AclEntry::kDefault | AclEntry::kUserObj)) { - newFile.acl = Acl(parent.acl, getUid(this->secCtx_), egid, mode, &newFile.stat.st_mode); - } -#endif - if (code == ENOENT) { + // Cleanup mode + mode = (mode & ~S_IFMT) | S_IFREG; + + // Effective gid + if (parent.stat.st_mode & S_ISGID) { + egid = parent.stat.st_gid; + mode |= S_ISGID; + } else { + egid = getGid(this->secCtx_); + } + + // Generate inherited ACL's if there are defaults + if (parent.acl.has(AclEntry::kDefault | AclEntry::kUserObj)) + newAcl = Acl(parent.acl, getUid(this->secCtx_), egid, mode, &mode); + // Create new wrapCall(f = fopen(lpath.c_str(), "w")); wrapCall(fclose(f)); + vfsSetOwner(path, lpath, getUid(this->secCtx_), egid, true); + vfsSetMode(path, lpath, mode); + if (!newAcl.empty()) + vfsSetAcl(path, lpath, newAcl); } else { // Truncate if (S_ISDIR(file.stat.st_mode)) @@ -590,11 +596,10 @@ void VfsCatalog::create(const std::string& path, mode_t mode) throw (DmException if (getUid(this->secCtx_) != file.stat.st_uid && checkPermissions(this->secCtx_, file.acl, file.stat, S_IWRITE) != 0) { vfsThrow(EACCES, "not enough permissions for '%s' to truncate '%s'", clientName.c_str(), path.c_str()); + // TODO: check replicas } wrapCall(truncate(lpath.c_str(), 0)); } - - setMode(path, mode); } @@ -612,6 +617,7 @@ mode_t VfsCatalog::umask(mode_t mask) throw () void VfsCatalog::setMode(const std::string& path, mode_t mode) throw (DmException) { ExtendedStat meta; + std::string lpath; if (vfsCheckPermissions(path, S_IWRITE)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); @@ -633,9 +639,31 @@ void VfsCatalog::setMode(const std::string& path, mode_t mode) throw (DmExceptio !hasGroup(this->secCtx_->groups, meta.stat.st_gid)) mode &= ~S_ISGID; - // TODO: update ACL, setAcl(). + // Update the ACL + if (!meta.acl.empty()) { + for (size_t i = 0; i < meta.acl.size(); ++i) { + switch (meta.acl[i].type) { + case AclEntry::kUserObj: + meta.acl[i].perm = mode >> 6 & 07; + break; + case AclEntry::kGroupObj: + case AclEntry::kMask: + meta.acl[i].perm = mode >> 3 & 07; + break; + case AclEntry::kOther: + meta.acl[i].perm = mode & 07; + break; + default: + continue; + } + } + } + + lpath = getLocalPath(path); - vfsSetMode(path, getLocalPath(path), mode); + vfsSetMode(path, lpath, mode); + if (!meta.acl.empty()) + vfsSetAcl(path, lpath, meta.acl); } @@ -644,7 +672,6 @@ void VfsCatalog::setOwner(const std::string& path, uid_t newUid, gid_t newGid, b { ExtendedStat meta; std::string lpath; - char buf[10]; if (vfsCheckPermissions(path, S_IWRITE)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); @@ -681,24 +708,23 @@ void VfsCatalog::setOwner(const std::string& path, uid_t newUid, gid_t newGid, b 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); - } + vfsSetOwner(path, lpath, meta, newUid, newGid, followSymLink); // 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; + switch (meta.acl[i].type) { + case AclEntry::kUserObj: + meta.acl[i].id = newUid; + break; + case AclEntry::kGroupObj: + meta.acl[i].id = newGid; + break; + default: + break; + } } - vfsSetXattr(path, lpath, VFS_XATTR "acl", buf, ATTR_DONTFOLLOW); + vfsSetXattr(path, lpath, VFS_XATTR "acl", meta.acl.serialize(), followSymLink ? 0 : ATTR_DONTFOLLOW); } } catch (DmException& e) { // xattrs are not supported on symbolic links @@ -767,7 +793,68 @@ void VfsCatalog::setChecksum(const std::string& path, void VfsCatalog::setAcl(const std::string& path, const Acl& acl) throw (DmException) { - throw DmException(EACCES, "Write mode not supported"); + ExtendedStat meta; + Acl aclCopy(acl); + std::string lpath; + + if (vfsCheckPermissions(path, S_IWRITE)) + vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); + + meta = this->vfsExtendedStat(path); + + // User has to be the owner, or root + if (getUid(this->secCtx_) != meta.stat.st_uid && + getUid(this->secCtx_) != 0) { + vfsThrow(EACCES, "'%s' neither owner nor root, setting ACL of '%s' rejected", clientName.c_str(), path.c_str()); + } + + // Make sure the owner and group matches! + for (size_t i = 0; i < aclCopy.size(); ++i) { + switch (aclCopy[i].type) { + case AclEntry::kUserObj: + aclCopy[i].id = meta.stat.st_uid; + break; + case AclEntry::kGroupObj: + aclCopy[i].id = meta.stat.st_gid; + break; + default: + if (aclCopy[i].type & AclEntry::kDefault && !S_ISDIR(meta.stat.st_mode)) + vfsThrow(EINVAL, "defaults can be only applied to directories"); + break; + } + } + + // Validate the ACL + aclCopy.validate(); + + // Update the file mode + for (size_t i = 0; i < aclCopy.size(); ++i) { + switch (aclCopy[i].type) { + case AclEntry::kUserObj: + meta.stat.st_mode = (meta.stat.st_mode & 0177077) | + (aclCopy[i].perm << 6); + break; + case AclEntry::kGroupObj: + meta.stat.st_mode = (meta.stat.st_mode & 0177707) | + (aclCopy[i].perm << 3); + break; + case AclEntry::kMask: + meta.stat.st_mode = (meta.stat.st_mode & ~070) | + (meta.stat.st_mode & aclCopy[i].perm << 3); + break; + case AclEntry::kOther: + meta.stat.st_mode = (meta.stat.st_mode & 0177770) | + (aclCopy[i].perm); + break; + default: + continue; + } + } + + lpath = getLocalPath(path); + + vfsSetMode(path, lpath, meta.stat.st_mode); + vfsSetAcl(path, lpath, aclCopy); } @@ -1427,3 +1514,34 @@ void VfsCatalog::vfsSetMode(const std::string& path, const std::string& lpath, m snprintf(buf, sizeof buf, "%04o", mode); vfsSetXattr(path, lpath, VFS_XATTR "mode", buf, 0); } + + + +void VfsCatalog::vfsSetOwner(const std::string& path, const std::string& lpath, uid_t newUid, gid_t newGid, bool followSymLink) throw (DmException) { + char buf[10]; + + if (newUid != (uid_t)-1) { + snprintf(buf, sizeof buf, "%u", newUid); + vfsSetXattr(path, lpath, VFS_XATTR "owner", buf, followSymLink ? 0 : ATTR_DONTFOLLOW); + } + if (newGid != (gid_t)-1) { + snprintf(buf, sizeof buf, "%u", newGid); + vfsSetXattr(path, lpath, VFS_XATTR "group", buf, followSymLink ? 0 : ATTR_DONTFOLLOW); + } +} + + + +void VfsCatalog::vfsSetOwner(const std::string& path, const std::string& lpath, const ExtendedStat& meta, uid_t newUid, gid_t newGid, bool followSymLink) throw (DmException) +{ + vfsSetOwner(path, lpath, newUid != meta.stat.st_uid ? newUid : (uid_t)-1, newGid != meta.stat.st_gid ? newGid : (gid_t)-1, followSymLink); +} + + + +void VfsCatalog::vfsSetAcl(const std::string& path, const std::string& lpath, Acl acl) throw (DmException) { + if (acl.empty()) + vfsRemoveXattr(path, lpath, VFS_XATTR "acl", 0); + else + vfsSetXattr(path, lpath, VFS_XATTR "acl", acl.serialize(), 0); +} diff --git a/src/VfsNs.h b/src/VfsNs.h index ece5e1f..9d602c7 100644 --- a/src/VfsNs.h +++ b/src/VfsNs.h @@ -119,6 +119,9 @@ namespace dmlite { bool vfsEvalRegex(regex_t *allowRegex, regex_t *denyRegex, const char *subj); int vfsCheckPermissions(const std::string& path, mode_t mode); void vfsSetMode(const std::string& path, const std::string& lpath, mode_t mode) throw (DmException); + void vfsSetOwner(const std::string& path, const std::string& lpath, uid_t newUid, gid_t newGid, bool followSymLink) throw (DmException); + void vfsSetOwner(const std::string& path, const std::string& lpath, const ExtendedStat& meta, uid_t newUid, gid_t newGid, bool followSymLink) throw (DmException); + void vfsSetAcl(const std::string& path, const std::string& lpath, Acl acl) throw (DmException); StackInstance* si_; const SecurityContext* secCtx_;