From fc382ec64c7fdd46398b3a4cfa2cbc9f5a171d83 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Thu, 17 Oct 2013 21:44:45 +0200 Subject: [PATCH] Initial support for VFS-related metadata in User Extended Attributes. --- src/VfsNs.cpp | 103 ++++++++++++++++++++++++++++++++++++++++++++++++---------- src/VfsNs.h | 7 ++-- 2 files changed, 90 insertions(+), 20 deletions(-) diff --git a/src/VfsNs.cpp b/src/VfsNs.cpp index 3ff977c..658546e 100644 --- a/src/VfsNs.cpp +++ b/src/VfsNs.cpp @@ -17,8 +17,19 @@ #include "Vfs.h" #include "VfsNs.h" +#define VFS_XATTR "#vfs." +#define VFS_XATTR_LENGTH 5 +#define VFS_XATTR_TYPE_PERMS 1 +#define VFS_XATTR_TYPE_NONPERMS 2 +#define VFS_XATTR_TYPE_USER 4 +#define VFS_XATTR_TYPE_ALL 7 +#define IS_VFS_XATTR(NAME) (strncmp((NAME), VFS_XATTR, VFS_XATTR_LENGTH) == 0) #define IS_VFS_FILE(NAME) (strncmp((NAME), VFS_FILE, VFS_FILE_LENGTH) == 0) +// force everything to current owner for now +#define VFS_UID_NONE xStat.stat.st_uid +#define VFS_GID_NONE xStat.stat.st_gid + using namespace dmlite; @@ -139,6 +150,24 @@ std::string VfsCatalog::getWorkingDir(void) throw (DmException) /// +/// Update ExtendedStat fields related to permissions. +/// Requires user extended attributes retrieved with VFS_XATTR_TYPE_PERMS or +/// VFS_XATTR_TYPE_ALL. +/// +/// @param xStat Updated ExtendedStat class. +/// @param xattrs User extended attributes (requires acl, group, and owner VFS +/// attributes). +/// +void VfsCatalog::vfsUpdateStat(ExtendedStat &xStat, Extensible xattrs) throw (DmException) { + if (xattrs.hasField(VFS_XATTR "acl")) + xStat.acl = Acl(xattrs.getString(VFS_XATTR "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); +} + + + +/// /// Do simple stat()/lstat() without setting st_nlink and checking permissions. /// Optionally retrieves also the information related to permissions in /// optimized way (using only attributes related to permissions). @@ -146,10 +175,12 @@ std::string VfsCatalog::getWorkingDir(void) throw (DmException) /// @param name file name /// @param path local disk namespace path /// @param follow follow symlinks (to use stat() or lstat()) +/// @param perms get information related to permissions // -ExtendedStat VfsCatalog::vfsSimpleStat(const std::string& name, const std::string& path, const std::string& lpath, bool follow) throw (DmException) { +ExtendedStat VfsCatalog::vfsSimpleStat(const std::string& name, const std::string& path, const std::string& lpath, bool follow, bool perms) throw (DmException) { ExtendedStat xStat; struct stat fstat; + Extensible xattrs; if (follow) wrapCall(stat(lpath.c_str(), &fstat), "could not stat '%s'", path.c_str()); @@ -162,6 +193,15 @@ ExtendedStat VfsCatalog::vfsSimpleStat(const std::string& name, const std::strin xStat.status = ExtendedStat::kOnline; xStat.acl = Acl(); + if (perms) { + xattrs = vfsGetXattrs(path, lpath, true, VFS_XATTR_TYPE_PERMS); + vfsUpdateStat(xStat, xattrs); + } else { + xStat.acl = Acl(); + xStat.stat.st_uid = VFS_UID_NONE; + xStat.stat.st_gid = VFS_GID_NONE; + } + return xStat; } @@ -174,8 +214,9 @@ ExtendedStat VfsCatalog::vfsSimpleStat(const std::string& name, const std::strin /// /// @param path public namespace path /// @param follow follow symlinks +/// @param parms get information related to permissions /// -ExtendedStat VfsCatalog::vfsExtendedStat(const std::string& path, bool follow) throw (DmException) { +ExtendedStat VfsCatalog::vfsExtendedStat(const std::string& path, bool follow, bool perms) throw (DmException) { ExtendedStat meta; std::vector components; std::string dir; @@ -191,13 +232,13 @@ ExtendedStat VfsCatalog::vfsExtendedStat(const std::string& path, bool follow) t if (i < 2) dir += components[i]; else dir = dir + "/" + components[i]; - meta = vfsSimpleStat(components[i], dir, getLocalPath(dir), true); + meta = vfsSimpleStat(components[i], dir, getLocalPath(dir), true, true); if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IEXEC) != 0) vfsThrow(EACCES, "not enough permissions for '%s' to list '%s'", clientName.c_str(), meta.name.c_str()); } - return vfsSimpleStat(components.back(), path, getLocalPath(path), follow); + return vfsSimpleStat(components.back(), path, getLocalPath(path), follow, perms); } @@ -212,21 +253,24 @@ ExtendedStat VfsCatalog::extendedStat(const std::string& path, bool follow) thro if (vfsCheckPermissions(path, S_IREAD)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); - meta = vfsExtendedStat(path, follow); + meta = vfsExtendedStat(path, follow, false); // // User extended attributes are not supported on symlinks. We need the same // owner, permissions and other atributes like the original file anyway. // ==> always follow the symlinks. // - xattrs = vfsGetXattrs(path, getLocalPath(path), true); + xattrs = vfsGetXattrs(path, getLocalPath(path), true, VFS_XATTR_TYPE_ALL); - // copy attributes + // copy non-VFS attributes for (it = xattrs.begin(); it != xattrs.end(); it++) { key = it->first; - meta[key] = xattrs[key]; + if (!IS_VFS_XATTR(key.c_str())) + meta[key] = xattrs[key]; } + vfsUpdateStat(meta, xattrs); + meta["pool"] = std::string("vfs"); #if 0 @@ -326,7 +370,7 @@ std::vector VfsCatalog::getReplicas(const std::string& path) throw (DmE if (vfsCheckPermissions(path, S_IREAD)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); - xStat = this->vfsExtendedStat(path, true); + xStat = this->vfsExtendedStat(path, true, true); if (checkPermissions(this->secCtx_, xStat.acl, xStat.stat, S_IREAD) != 0) vfsThrow(EACCES, "not enough permissions for '%s' to read '%s'", clientName.c_str(), path.c_str()); @@ -381,7 +425,7 @@ std::string VfsCatalog::readLink(const std::string& path) throw (DmException) if (vfsCheckPermissions(path, S_IREAD)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); - meta = this->vfsExtendedStat(path, false); + meta = this->vfsExtendedStat(path, false, true); if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IREAD) != 0) vfsThrow(EACCES, "not enough permissions for '%s' on '%s'", clientName.c_str(), path.c_str()); @@ -416,7 +460,7 @@ void VfsCatalog::unlink(const std::string& path) throw (DmException) // Sticky bit set ==> only directory or file owner can delete if ((parent.stat.st_mode & S_ISVTX) == S_ISVTX) { // not follow symlinks (remove them instead) - ExtendedStat file = this->vfsSimpleStat(name, path, lpath, false); + ExtendedStat file = this->vfsSimpleStat(name, path, lpath, false, true); if (getUid(this->secCtx_) != file.stat.st_uid && getUid(this->secCtx_) != parent.stat.st_uid) { vfsThrow(EACCES, "not enough permissions for '%s' to unlink '%s' (sticky bit set)", clientName.c_str(), path.c_str()); @@ -449,7 +493,7 @@ void VfsCatalog::create(const std::string& path, mode_t mode) throw (DmException try { // follow symlinks - file = this->vfsSimpleStat(name, path, lpath, true); + file = this->vfsSimpleStat(name, path, lpath, true, true); } catch (DmException e) { code = DMLITE_ERRNO(e.code()); if (code != ENOENT) throw; @@ -636,6 +680,10 @@ void VfsCatalog::updateExtendedAttributes(const std::string& path, for (it = newXattrs.begin(); it != newXattrs.end(); it++) { key = it->first; + // not synchronize anything VFS plugin related + if (IS_VFS_XATTR(key.c_str())) + vfsThrow(EPERM, "change VFS plugin attribute not permitted (%s)", key.c_str()); + // used to be bug in Extensible? bool type "true" not mapped to true //if (it->second.type() == typeid(bool)) value = Extensible::anyToBoolean(it->second) ? std::string("1") : std::string("0"); //else value = Extensible::anyToString(it->second); @@ -657,6 +705,10 @@ void VfsCatalog::updateExtendedAttributes(const std::string& path, for (it = oldXattrs.begin(); it != oldXattrs.end(); it++) { key = it->first; + // not synchronize anything VFS plugin related + if (IS_VFS_XATTR(key.c_str())) + vfsThrow(DMLITE_SYSERR(EINVAL), "internal error: got VFS plugin attribute from extendedStat(), this should not happen"); + value = Extensible::anyToString(it->second); debug("removing '%s' = '%s' from '%s'", key.c_str(), value.c_str(), lpath.c_str()); wrapCall(attr_remove(lpath.c_str(), key.c_str(), 0), "could not remove '%s' on '%s'", key.c_str(), path.c_str()); @@ -1035,13 +1087,18 @@ int VfsCatalog::checkPermissions(const SecurityContext *context, const Acl &acl, /// /// @param path local disk namespace path /// @param follow follow symlinks (not well supported, it should be always true), XXX: dangling symlinks fails -Extensible VfsCatalog::vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow) throw (DmException) { +/// @param amount what to retrieve, bitmask: +/// VFS_XATTR_TYPE_PERMS = 1: permissions related attributes (#vfs.acl, #vfs.owner, #vfs.group, ...), +/// VFS_XATTR_TYPE_NONPERMS = 2: other VFS plugin related attributes (#vfs.replica*, ...), +/// VFS_XATTR_TYPE_USER = 4: user attributes +Extensible VfsCatalog::vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow, int amount) throw (DmException) { int len; std::string attrValue; Extensible xattrs; attrlist_cursor_t attr_cursor; attrlist_t *list; attrlist_ent_t *entry; + int attrType; list = (attrlist_t *)this->buffer; memset(&attr_cursor, 0, sizeof attr_cursor); @@ -1049,13 +1106,25 @@ Extensible VfsCatalog::vfsGetXattrs(const std::string& path, const std::string& wrapCall(attr_list(lpath.c_str(), this->buffer, sizeof this->buffer, follow ? 0 : ATTR_DONTFOLLOW, &attr_cursor), "could not get list of extended attributes on '%s'", path.c_str()); for (int i = 0; i < list->al_count; i++) { entry = ATTR_ENTRY(this->buffer, i); - // "selinux" is returned in the list, but failing to get the value - if (strcmp(entry->a_name, "selinux") == 0) { - //debug("skipping attribute '%s'", entry->a_name); + 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, "owner") == 0) + { + attrType = VFS_XATTR_TYPE_PERMS; + } else { + attrType = VFS_XATTR_TYPE_NONPERMS; + } } else { + // "selinux" is returned in the list, but failing to get the value + if (strcmp(entry->a_name, "selinux") == 0) attrType = 0; + else attrType = VFS_XATTR_TYPE_USER; + } + + if ((attrType & amount) != 0) { len = sizeof this->xattrValue; wrapCall(attr_get(lpath.c_str(), entry->a_name, this->xattrValue, &len, follow ? 0 : ATTR_DONTFOLLOW), "could not get extended attribute '%s' on '%s'", entry->a_name, path.c_str()); - debug("'%s' = '%.*s'", entry->a_name, len, this->xattrValue); + debug("'%s' (type %d) = '%.*s'", entry->a_name, attrType, len, this->xattrValue); attrValue.assign(this->xattrValue, len); xattrs[entry->a_name] = attrValue; } diff --git a/src/VfsNs.h b/src/VfsNs.h index 33f9558..33c1e4f 100644 --- a/src/VfsNs.h +++ b/src/VfsNs.h @@ -106,10 +106,11 @@ namespace dmlite { /// Get path on the local disk according to "public" path. /// Relative paths are unchanged. const std::string getLocalPath(const std::string &path); - ExtendedStat vfsSimpleStat(const std::string& name, const std::string& path, const std::string& lpath, bool follow) throw (DmException); - ExtendedStat vfsExtendedStat(const std::string& path, bool follow = true) throw (DmException); + void vfsUpdateStat(ExtendedStat &xStat, Extensible xattrs) throw (DmException); + ExtendedStat vfsSimpleStat(const std::string& name, const std::string& path, const std::string& lpath, bool follow, bool perms) throw (DmException); + ExtendedStat vfsExtendedStat(const std::string& path, bool follow = true, bool perms = true) throw (DmException); PrivateDir* vfsOpenDir(const std::string& lpath, const std::string& path) throw (DmException); - Extensible vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow) throw (DmException); + Extensible vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow, int amount) throw (DmException); void vfsSetXattr(const std::string& path, const std::string& lpath, const std::string key, const std::string value, int flags); regex_t *vfsCompileRegex(const char *name, const std::string value) throw (DmException); bool vfsEvalRegex(regex_t *allowRegex, regex_t *denyRegex, const char *subj); -- 1.8.2.3