diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2019-05-23 17:11:23 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2019-05-24 09:00:50 -0400 |
commit | d9b3196d6c8f4fa0e7d0a4771040762edaebb1ee (patch) | |
tree | f378d6955cf3cd6817a47e3a95284441552b221e /posix1e.c | |
parent | 28bbaeac8058653a4a46ae439c37d251a550f4f9 (diff) | |
download | bfs-d9b3196d6c8f4fa0e7d0a4771040762edaebb1ee.tar.xz |
fsade: Refactor the POSIX.1e abstractions
Since we're going to want to abstract more things that aren't part of
POSIX.1e (like xattrs) in a similar way, let's give this a more generic
name. And while we're at it, give it some more precise error reporting,
and add some tests.
Diffstat (limited to 'posix1e.c')
-rw-r--r-- | posix1e.c | 192 |
1 files changed, 0 insertions, 192 deletions
diff --git a/posix1e.c b/posix1e.c deleted file mode 100644 index a898b39..0000000 --- a/posix1e.c +++ /dev/null @@ -1,192 +0,0 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019 Tavian Barnes <tavianator@tavianator.com> * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ - -#include "posix1e.h" -#include "bftw.h" -#include "util.h" -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#if BFS_HAS_SYS_ACL -# include <sys/acl.h> -#endif - -#if BFS_HAS_POSIX1E_CAPABILITIES -# include <sys/capability.h> -#endif - -#if BFS_HAS_SYS_ACL || BFS_HAS_POSIX1E_CAPABILITIES - -static const char *open_path(const struct BFTW *ftwbuf, int *fd) { -#ifdef O_PATH - // The POSIX.1e APIS predate the *at() family of functions. We'd still - // like to do something to avoid path re-traversals and limit races - // though. Ideally we could just do openat(..., O_PATH) (since we may - // not have read access) and pass that fd to something like cap_get_fd() - // but that will fail since fgetxattr() needs read access to the file. - // The workaround is to use O_PATH to open an fd and then pass - // /proc/self/fd/<fd> to cap_get_path(). Inspired by - // https://android.googlesource.com/platform/bionic/+/2825f10b7f61558c264231a536cf3affc0d84204 - int flags = O_PATH; - if (ftwbuf->stat_flags & BFS_STAT_NOFOLLOW) { - flags |= O_NOFOLLOW; - } - - *fd = openat(ftwbuf->at_fd, ftwbuf->at_path, flags); - if (*fd < 0) { - return NULL; - } - - size_t size = strlen("/proc/self/fd/") + CHAR_BIT*sizeof(int) + 1; - char *path = malloc(size); - if (!path) { - close(*fd); - *fd = -1; - return NULL; - } - - snprintf(path, size, "/proc/self/fd/%d", *fd); - return path; -#else - *fd = -1; - return ftwbuf->path; -#endif -} - -static void close_path(const struct BFTW *ftwbuf, const char *path, int fd) { - if (path && path != ftwbuf->path) { - free((void *)path); - } - if (fd >= 0) { - close(fd); - } -} - -#endif // BFS_HAS_SYS_ACL || BFS_HAS_POSIX1E_CAPABILITIES - -#if BFS_HAS_SYS_ACL - -/** Check if any ACLs of the given type are non-trivial. */ -static bool bfs_check_acl_type(const char *path, acl_type_t type) { - acl_t acl = acl_get_file(path, type); - if (!acl) { - return false; - } - - bool ret = false; - acl_entry_t entry; - for (int status = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); - status > 0; - status = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { -#if defined(ACL_USER_OBJ) && defined(ACL_GROUP_OBJ) && defined(ACL_OTHER) - acl_tag_t tag; - if (acl_get_tag_type(entry, &tag) != 0) { - continue; - } - if (tag != ACL_USER_OBJ && tag != ACL_GROUP_OBJ && tag != ACL_OTHER) { - ret = true; - break; - } -#else - ret = true; - break; -#endif - } - - acl_free(acl); - return ret; -} - -bool bfs_check_acl(const struct BFTW *ftwbuf) { - if (ftwbuf->typeflag == BFTW_LNK) { - return false; - } - - int fd; - const char *path = open_path(ftwbuf, &fd); - if (!path) { - return false; - } - - bool ret = false; - if (bfs_check_acl_type(path, ACL_TYPE_ACCESS)) { - ret = true; - } else if (bfs_check_acl_type(path, ACL_TYPE_DEFAULT)) { - ret = true; -#ifdef ACL_TYPE_EXTENDED - } else if (bfs_check_acl_type(path, ACL_TYPE_EXTENDED)) { - ret = true; -#endif - } - - close_path(ftwbuf, path, fd); - return ret; -} - -#else // !BFS_HAS_SYS_ACL - -bool bfs_check_acl(const struct BFTW *ftwbuf) { - return false; -} - -#endif - -#if BFS_HAS_POSIX1E_CAPABILITIES - -bool bfs_check_capabilities(const struct BFTW *ftwbuf) { - bool ret = false; - - if (ftwbuf->typeflag == BFTW_LNK) { - goto out; - } - - int fd; - const char *path = open_path(ftwbuf, &fd); - if (!path) { - goto out; - } - - cap_t caps = cap_get_file(path); - if (!caps) { - goto out_close; - } - - // TODO: Any better way to check for a non-empty capability set? - char *text = cap_to_text(caps, NULL); - if (!text) { - goto out_free_caps; - } - ret = text[0]; - - cap_free(text); -out_free_caps: - cap_free(caps); -out_close: - close_path(ftwbuf, path, fd); -out: - return ret; -} - -#else // !BFS_HAS_POSIX1E_CAPABILITIES - -bool bfs_check_capabilities(const struct BFTW *ftwbuf) { - return false; -} - -#endif |