| /* |
| * Copyright (c) 1997,2007 Andrew G Morgan <morgan@kernel.org> |
| * |
| * This file deals with setting capabilities on files. |
| */ |
| |
| #include <sys/types.h> |
| #include <attr/xattr.h> |
| #include <byteswap.h> |
| |
| #define XATTR_SECURITY_PREFIX "security." |
| |
| #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) |
| { |
| __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; |
| break; |
| #endif |
| |
| #ifdef VFS_CAP_REVISION_2 |
| case VFS_CAP_REVISION_2: |
| tocopy = VFS_CAP_U32_2; |
| break; |
| #endif |
| |
| default: |
| 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) |
| { |
| __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; |
| break; |
| #endif |
| |
| #ifdef _LINUX_CAPABILITY_VERSION_2 |
| case _LINUX_CAPABILITY_VERSION_2: |
| magic = VFS_CAP_REVISION_2; |
| tocopy = VFS_CAP_U32_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; |
| |
| _cap_debug("getting fildes capabilities"); |
| |
| /* fill the capability sets via a system call */ |
| if (sizeof(rawvfscap) != fgetxattr(fildes, XATTR_NAME_CAPS, |
| &rawvfscap, sizeof(rawvfscap))) { |
| cap_free(result); |
| result = NULL; |
| } else { |
| result = _fcaps_load(&rawvfscap, result); |
| } |
| } |
| |
| return result; |
| } |
| |
| /* |
| * Set the capabilities on 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; |
| |
| _cap_debug("getting filename capabilities"); |
| |
| /* fill the capability sets via a system call */ |
| if (sizeof(rawvfscap) != getxattr(filename, XATTR_NAME_CAPS, |
| &rawvfscap, sizeof(rawvfscap))) { |
| cap_free(result); |
| result = NULL; |
| } else { |
| result = _fcaps_load(&rawvfscap, result); |
| } |
| } |
| |
| 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; |
| |
| if (cap_d == NULL) { |
| _cap_debug("deleting fildes capabilities"); |
| return fremovexattr(fildes, XATTR_NAME_CAPS); |
| } else if (_fcaps_save(&rawvfscap, cap_d) != 0) { |
| return -1; |
| } |
| |
| _cap_debug("setting fildes capabilities"); |
| |
| return fsetxattr(fildes, XATTR_NAME_CAPS, &rawvfscap, |
| sizeof(rawvfscap), 0); |
| } |
| |
| /* |
| * Set the capabilities of a named file. |
| */ |
| |
| int cap_set_file(const char *filename, cap_t cap_d) |
| { |
| struct vfs_cap_data rawvfscap; |
| |
| if (cap_d == NULL) { |
| _cap_debug("removing filename capabilities"); |
| return removexattr(filename, XATTR_NAME_CAPS); |
| } else if (_fcaps_save(&rawvfscap, cap_d) != 0) { |
| return -1; |
| } |
| |
| _cap_debug("setting filename capabilities"); |
| return setxattr(filename, XATTR_NAME_CAPS, &rawvfscap, |
| sizeof(rawvfscap), 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 */ |