123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /*
- * Copyright (c) 1997,2007,2016 Andrew G Morgan <morgan@kernel.org>
- *
- * This file deals with setting capabilities on files.
- */
- #include <sys/types.h>
- #include <byteswap.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <linux/xattr.h>
- /*
- * We hardcode the prototypes for the Linux system calls here since
- * there are no libcap library APIs that expose the user to these
- * details, and that way we don't need to foce clients to link any
- * other libraries to access them.
- */
- extern ssize_t getxattr(const char *, const char *, void *, size_t);
- extern ssize_t fgetxattr(int, const char *, void *, size_t);
- extern int setxattr(const char *, const char *, const void *, size_t, int);
- extern int fsetxattr(int, const char *, const void *, size_t, int);
- extern int removexattr(const char *, const char *);
- extern int fremovexattr(int, const char *);
- #include "libcap.h"
- #ifdef VFS_CAP_U32
- #if VFS_CAP_U32 != __CAP_BLKS
- # error VFS representation of capabilities is not the same size as kernel
- #endif
- #if __BYTE_ORDER == __BIG_ENDIAN
- #define FIXUP_32BITS(x) bswap_32(x)
- #else
- #define FIXUP_32BITS(x) (x)
- #endif
- static cap_t _fcaps_load(struct vfs_cap_data *rawvfscap, cap_t result,
- int bytes)
- {
- __u32 magic_etc;
- unsigned tocopy, i;
- magic_etc = FIXUP_32BITS(rawvfscap->magic_etc);
- switch (magic_etc & VFS_CAP_REVISION_MASK) {
- #ifdef VFS_CAP_REVISION_1
- case VFS_CAP_REVISION_1:
- tocopy = VFS_CAP_U32_1;
- bytes -= XATTR_CAPS_SZ_1;
- break;
- #endif
- #ifdef VFS_CAP_REVISION_2
- case VFS_CAP_REVISION_2:
- tocopy = VFS_CAP_U32_2;
- bytes -= XATTR_CAPS_SZ_2;
- break;
- #endif
- default:
- cap_free(result);
- result = NULL;
- return result;
- }
- /*
- * Verify that we loaded exactly the right number of bytes
- */
- if (bytes != 0) {
- cap_free(result);
- result = NULL;
- return result;
- }
- for (i=0; i < tocopy; i++) {
- result->u[i].flat[CAP_INHERITABLE]
- = FIXUP_32BITS(rawvfscap->data[i].inheritable);
- result->u[i].flat[CAP_PERMITTED]
- = FIXUP_32BITS(rawvfscap->data[i].permitted);
- if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
- result->u[i].flat[CAP_EFFECTIVE]
- = result->u[i].flat[CAP_INHERITABLE]
- | result->u[i].flat[CAP_PERMITTED];
- }
- }
- while (i < __CAP_BLKS) {
- result->u[i].flat[CAP_INHERITABLE]
- = result->u[i].flat[CAP_PERMITTED]
- = result->u[i].flat[CAP_EFFECTIVE] = 0;
- i++;
- }
- return result;
- }
- static int _fcaps_save(struct vfs_cap_data *rawvfscap, cap_t cap_d,
- int *bytes_p)
- {
- __u32 eff_not_zero, magic;
- unsigned tocopy, i;
- if (!good_cap_t(cap_d)) {
- errno = EINVAL;
- return -1;
- }
- switch (cap_d->head.version) {
- #ifdef _LINUX_CAPABILITY_VERSION_1
- case _LINUX_CAPABILITY_VERSION_1:
- magic = VFS_CAP_REVISION_1;
- tocopy = VFS_CAP_U32_1;
- *bytes_p = XATTR_CAPS_SZ_1;
- break;
- #endif
- #ifdef _LINUX_CAPABILITY_VERSION_2
- case _LINUX_CAPABILITY_VERSION_2:
- magic = VFS_CAP_REVISION_2;
- tocopy = VFS_CAP_U32_2;
- *bytes_p = XATTR_CAPS_SZ_2;
- break;
- #endif
- #ifdef _LINUX_CAPABILITY_VERSION_3
- case _LINUX_CAPABILITY_VERSION_3:
- magic = VFS_CAP_REVISION_2;
- tocopy = VFS_CAP_U32_2;
- *bytes_p = XATTR_CAPS_SZ_2;
- break;
- #endif
- default:
- errno = EINVAL;
- return -1;
- }
- _cap_debug("setting named file capabilities");
- for (eff_not_zero = 0, i = 0; i < tocopy; i++) {
- eff_not_zero |= cap_d->u[i].flat[CAP_EFFECTIVE];
- }
- while (i < __CAP_BLKS) {
- if ((cap_d->u[i].flat[CAP_EFFECTIVE]
- || cap_d->u[i].flat[CAP_INHERITABLE]
- || cap_d->u[i].flat[CAP_PERMITTED])) {
- /*
- * System does not support these capabilities
- */
- errno = EINVAL;
- return -1;
- }
- i++;
- }
- for (i=0; i < tocopy; i++) {
- rawvfscap->data[i].permitted
- = FIXUP_32BITS(cap_d->u[i].flat[CAP_PERMITTED]);
- rawvfscap->data[i].inheritable
- = FIXUP_32BITS(cap_d->u[i].flat[CAP_INHERITABLE]);
- if (eff_not_zero
- && ((~(cap_d->u[i].flat[CAP_EFFECTIVE]))
- & (cap_d->u[i].flat[CAP_PERMITTED]
- | cap_d->u[i].flat[CAP_INHERITABLE]))) {
- errno = EINVAL;
- return -1;
- }
- }
- if (eff_not_zero == 0) {
- rawvfscap->magic_etc = FIXUP_32BITS(magic);
- } else {
- rawvfscap->magic_etc = FIXUP_32BITS(magic|VFS_CAP_FLAGS_EFFECTIVE);
- }
- return 0; /* success */
- }
- /*
- * Get the capabilities of an open file, as specified by its file
- * descriptor.
- */
- cap_t cap_get_fd(int fildes)
- {
- cap_t result;
- /* allocate a new capability set */
- result = cap_init();
- if (result) {
- struct vfs_cap_data rawvfscap;
- int sizeofcaps;
- _cap_debug("getting fildes capabilities");
- /* fill the capability sets via a system call */
- sizeofcaps = fgetxattr(fildes, XATTR_NAME_CAPS,
- &rawvfscap, sizeof(rawvfscap));
- if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) {
- cap_free(result);
- result = NULL;
- } else {
- result = _fcaps_load(&rawvfscap, result, sizeofcaps);
- }
- }
- return result;
- }
- /*
- * Get the capabilities from a named file.
- */
- cap_t cap_get_file(const char *filename)
- {
- cap_t result;
- /* allocate a new capability set */
- result = cap_init();
- if (result) {
- struct vfs_cap_data rawvfscap;
- int sizeofcaps;
- _cap_debug("getting filename capabilities");
- /* fill the capability sets via a system call */
- sizeofcaps = getxattr(filename, XATTR_NAME_CAPS,
- &rawvfscap, sizeof(rawvfscap));
- if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) {
- cap_free(result);
- result = NULL;
- } else {
- result = _fcaps_load(&rawvfscap, result, sizeofcaps);
- }
- }
- return result;
- }
- /*
- * Set the capabilities of an open file, as specified by its file
- * descriptor.
- */
- int cap_set_fd(int fildes, cap_t cap_d)
- {
- struct vfs_cap_data rawvfscap;
- int sizeofcaps;
- struct stat buf;
- if (fstat(fildes, &buf) != 0) {
- _cap_debug("unable to stat file descriptor %d", fildes);
- return -1;
- }
- if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) {
- _cap_debug("file descriptor %d for non-regular file", fildes);
- errno = EINVAL;
- return -1;
- }
- if (cap_d == NULL) {
- _cap_debug("deleting fildes capabilities");
- return fremovexattr(fildes, XATTR_NAME_CAPS);
- } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) {
- return -1;
- }
- _cap_debug("setting fildes capabilities");
- return fsetxattr(fildes, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0);
- }
- /*
- * Set the capabilities of a named file.
- */
- int cap_set_file(const char *filename, cap_t cap_d)
- {
- struct vfs_cap_data rawvfscap;
- int sizeofcaps;
- struct stat buf;
- if (lstat(filename, &buf) != 0) {
- _cap_debug("unable to stat file [%s]", filename);
- return -1;
- }
- if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) {
- _cap_debug("file [%s] is not a regular file", filename);
- errno = EINVAL;
- return -1;
- }
- if (cap_d == NULL) {
- _cap_debug("removing filename capabilities");
- return removexattr(filename, XATTR_NAME_CAPS);
- } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) {
- return -1;
- }
- _cap_debug("setting filename capabilities");
- return setxattr(filename, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0);
- }
- #else /* ie. ndef VFS_CAP_U32 */
- cap_t cap_get_fd(int fildes)
- {
- errno = EINVAL;
- return NULL;
- }
- cap_t cap_get_file(const char *filename)
- {
- errno = EINVAL;
- return NULL;
- }
- int cap_set_fd(int fildes, cap_t cap_d)
- {
- errno = EINVAL;
- return -1;
- }
- int cap_set_file(const char *filename, cap_t cap_d)
- {
- errno = EINVAL;
- return -1;
- }
- #endif /* def VFS_CAP_U32 */
|