aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Morgan <morgan@kernel.org>2007-10-31 23:18:09 -0700
committerAndrew Morgan <morgan@kernel.org>2007-10-31 23:18:09 -0700
commitea4e5f8e08bf8af459378dac24d42fdbbcdb2e73 (patch)
treee54994e1dbb4f23a7dbdf3233486d24d035c11dd
parente668cd62a296f740c6cc36e290ec0a2df243ad6b (diff)
downloadlibcap-ea4e5f8e08bf8af459378dac24d42fdbbcdb2e73.tar.gz
Add support for 64-bit (file) capabilitieslibcap-20071031
This should compile with any iteration of a recent (2.6) kernel. If your kernel has 64-bit capabilities support, and the kernel headers indicate this, then it will include that. 32-bit legacy kernel support is dynamically performed by such a build of libcap.
-rw-r--r--libcap/cap_alloc.c16
-rw-r--r--libcap/cap_extint.c11
-rw-r--r--libcap/cap_file.c145
-rw-r--r--libcap/cap_flag.c16
-rw-r--r--libcap/cap_proc.c12
-rw-r--r--libcap/cap_text.c95
-rw-r--r--libcap/include/sys/capability.h1
-rw-r--r--libcap/libcap.h101
-rw-r--r--progs/getpcaps.c8
-rw-r--r--progs/setcap.c31
10 files changed, 303 insertions, 133 deletions
diff --git a/libcap/cap_alloc.c b/libcap/cap_alloc.c
index a3b22a7..78df97c 100644
--- a/libcap/cap_alloc.c
+++ b/libcap/cap_alloc.c
@@ -29,6 +29,22 @@ cap_t cap_init(void)
memset(result, 0, sizeof(*result));
result->head.version = _LINUX_CAPABILITY_VERSION;
+ capget(&result->head, NULL); /* load the kernel-capability version */
+
+ switch (result->head.version) {
+#ifdef _LINUX_CAPABILITY_VERSION_1
+ case _LINUX_CAPABILITY_VERSION_1:
+ break;
+#endif
+#ifdef _LINUX_CAPABILITY_VERSION_2
+ case _LINUX_CAPABILITY_VERSION_2:
+ break;
+#endif
+ default: /* No idea what to do */
+ cap_free(result);
+ result = NULL;
+ break;
+ }
return result;
}
diff --git a/libcap/cap_extint.c b/libcap/cap_extint.c
index 1d858a1..4cf43ea 100644
--- a/libcap/cap_extint.c
+++ b/libcap/cap_extint.c
@@ -41,7 +41,6 @@ ssize_t cap_size(cap_t caps)
ssize_t cap_copy_ext(void *cap_ext, cap_t cap_d, ssize_t length)
{
struct cap_ext_struct *result = (struct cap_ext_struct *) cap_ext;
- __u32 *from = (__u32 *) &(cap_d->set);
int i;
/* valid arguments? */
@@ -58,7 +57,9 @@ ssize_t cap_copy_ext(void *cap_ext, cap_t cap_d, ssize_t length)
for (i=0; i<NUMBER_OF_CAP_SETS; ++i) {
int j;
for (j=0; j<CAP_SET_SIZE; ) {
- __u32 val = *from++;
+ __u32 val;
+
+ val = cap_d->u[j/sizeof(__u32)].flat[i];
result->bytes[j++][i] = val & 0xFF;
result->bytes[j++][i] = (val >>= 8) & 0xFF;
@@ -87,7 +88,6 @@ cap_t cap_copy_int(const void *cap_ext)
(const struct cap_ext_struct *) cap_ext;
cap_t cap_d;
int set, blen;
- __u32 * to;
/* Does the external representation make sense? */
if (export == NULL || !memcmp(export->magic, external_magic
@@ -100,12 +100,11 @@ cap_t cap_copy_int(const void *cap_ext)
if (!(cap_d = cap_init()))
return NULL;
- to = (__u32 *) &cap_d->set;
blen = export->length_of_capset;
for (set=0; set<=NUMBER_OF_CAP_SETS; ++set) {
int blk;
int bno = 0;
- for (blk=0; blk<(CAP_SET_SIZE/4); ++blk) {
+ for (blk=0; blk<(CAP_SET_SIZE/sizeof(__u32)); ++blk) {
__u32 val = 0;
if (bno != blen)
@@ -117,7 +116,7 @@ cap_t cap_copy_int(const void *cap_ext)
if (bno != blen)
val |= export->bytes[bno++][set] << 24;
- *to++ = val;
+ cap_d->u[blk].flat[set];
}
}
diff --git a/libcap/cap_file.c b/libcap/cap_file.c
index 90a2c40..f1020a9 100644
--- a/libcap/cap_file.c
+++ b/libcap/cap_file.c
@@ -12,6 +12,11 @@
#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
@@ -21,22 +26,44 @@
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:
- result->set.inheritable =
- FIXUP_32BITS(rawvfscap->data[0].inheritable);
- result->set.permitted =
- FIXUP_32BITS(rawvfscap->data[0].permitted);
- if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
- result->set.effective =
- result->set.inheritable | result->set.permitted;
- }
+ 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;
@@ -44,26 +71,72 @@ static cap_t _fcaps_load(struct vfs_cap_data *rawvfscap, cap_t 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;
}
- _cap_debug("setting named file capabilities");
+ 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
- if (cap_d->set.effective == 0) {
- rawvfscap->magic_etc = FIXUP_32BITS(VFS_CAP_REVISION);
- } else if ((~(cap_d->set.effective))
- & (cap_d->set.inheritable|cap_d->set.permitted)) {
+ default:
errno = EINVAL;
return -1;
- } else {
- rawvfscap->magic_etc
- = FIXUP_32BITS(VFS_CAP_REVISION|VFS_CAP_FLAGS_EFFECTIVE);
}
- rawvfscap->data[0].permitted = FIXUP_32BITS(cap_d->set.permitted);
- rawvfscap->data[0].inheritable = FIXUP_32BITS(cap_d->set.inheritable);
+ _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 */
}
@@ -89,9 +162,9 @@ cap_t cap_get_fd(int fildes)
&rawvfscap, sizeof(rawvfscap))) {
cap_free(result);
result = NULL;
+ } else {
+ result = _fcaps_load(&rawvfscap, result);
}
-
- result = _fcaps_load(&rawvfscap, result);
}
return result;
@@ -117,9 +190,9 @@ cap_t cap_get_file(const char *filename)
&rawvfscap, sizeof(rawvfscap))) {
cap_free(result);
result = NULL;
+ } else {
+ result = _fcaps_load(&rawvfscap, result);
}
-
- result = _fcaps_load(&rawvfscap, result);
}
return result;
@@ -166,3 +239,31 @@ int cap_set_file(const char *filename, cap_t cap_d)
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 */
diff --git a/libcap/cap_flag.c b/libcap/cap_flag.c
index a8567c0..e521fcd 100644
--- a/libcap/cap_flag.c
+++ b/libcap/cap_flag.c
@@ -23,18 +23,12 @@ int cap_get_flag(cap_t cap_d, cap_value_t value, cap_flag_t set,
if (raised && good_cap_t(cap_d) && value >= 0 && value < __CAP_BITS
&& set >= 0 && set < NUMBER_OF_CAP_SETS) {
- __cap_s *cap_p = (__cap_s *) (set*CAP_SET_SIZE
- + (__u8 *) &cap_d->set);
-
- *raised = isset_cap(cap_p,value) ? CAP_SET:CAP_CLEAR;
+ *raised = isset_cap(cap_d,value,set) ? CAP_SET:CAP_CLEAR;
return 0;
-
} else {
-
_cap_debug("invalid arguments");
errno = EINVAL;
return -1;
-
}
}
@@ -60,13 +54,11 @@ int cap_set_flag(cap_t cap_d, cap_flag_t set,
_cap_debug("weird capability (%d) - skipped", array_values[i]);
} else {
int value = array_values[i];
- __cap_s *cap_p = (__cap_s *) (set*CAP_SET_SIZE
- + (__u8 *) &cap_d->set);
if (raise == CAP_SET) {
- cap_p->raise_cap(value);
+ cap_d->raise_cap(value,set);
} else {
- cap_p->lower_cap(value);
+ cap_d->lower_cap(value,set);
}
}
}
@@ -89,7 +81,7 @@ int cap_clear(cap_t cap_d)
{
if (good_cap_t(cap_d)) {
- memset(&(cap_d->set), 0, sizeof(cap_d->set));
+ memset(&(cap_d->u), 0, sizeof(cap_d->u));
return 0;
} else {
diff --git a/libcap/cap_proc.c b/libcap/cap_proc.c
index 5c2ac48..40793b4 100644
--- a/libcap/cap_proc.c
+++ b/libcap/cap_proc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-8 Andrew G Morgan <morgan@kernel.org>
+ * Copyright (c) 1997-8,2007 Andrew G Morgan <morgan@kernel.org>
*
* This file deals with setting capabilities on processes.
*/
@@ -16,7 +16,7 @@ cap_t cap_get_proc(void)
_cap_debug("getting current process' capabilities");
/* fill the capability sets via a system call */
- if (capget(&result->head, &result->set)) {
+ if (capget(&result->head, &result->u[0].set)) {
cap_free(result);
result = NULL;
}
@@ -35,9 +35,8 @@ int cap_set_proc(cap_t cap_d)
}
_cap_debug("setting process capabilities");
- retval = capset(&cap_d->head, &cap_d->set);
+ retval = capset(&cap_d->head, &cap_d->u[0].set);
- cap_d->head.version = _LINUX_CAPABILITY_VERSION;
return retval;
}
@@ -57,8 +56,7 @@ int capgetp(pid_t pid, cap_t cap_d)
_cap_debug("getting process capabilities for proc %d", pid);
cap_d->head.pid = pid;
- error = capget(&cap_d->head, &cap_d->set);
- cap_d->head.version = _LINUX_CAPABILITY_VERSION;
+ error = capget(&cap_d->head, &cap_d->u[0].set);
cap_d->head.pid = 0;
return error;
@@ -77,7 +75,7 @@ int capsetp(pid_t pid, cap_t cap_d)
_cap_debug("setting process capabilities for proc %d", pid);
cap_d->head.pid = pid;
- error = capset(&cap_d->head, &cap_d->set);
+ error = capset(&cap_d->head, &cap_d->u[0].set);
cap_d->head.version = _LINUX_CAPABILITY_VERSION;
cap_d->head.pid = 0;
diff --git a/libcap/cap_text.c b/libcap/cap_text.c
index 5814093..06f61d9 100644
--- a/libcap/cap_text.c
+++ b/libcap/cap_text.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-8 Andrew G Morgan <morgan@kernel.org>
+ * Copyright (c) 1997-8,2007 Andrew G Morgan <morgan@kernel.org>
* Copyright (c) 1997 Andrew Main <zefram@dcs.warwick.ac.uk>
*
* This file deals with exchanging internal and textual
@@ -24,20 +24,21 @@
* representation.
*/
-#define setbits(A,B) _setbits((__cap_s *)A, (__cap_s *)B)
-static void _setbits(__cap_s *a, __cap_s *b)
+#define raise_cap_mask(flat, c) (flat)[CAP_TO_INDEX(c)] |= CAP_TO_MASK(c)
+
+static void setbits(cap_t a, const __u32 *b, cap_flag_t set)
{
int n;
- for (n = __CAP_BLKS; n--; )
- a->_blk[n] |= b->_blk[n];
+ for (n = __CAP_BLKS; n--; ) {
+ a->u[n].flat[set] |= b[n];
+ }
}
-#define clrbits(A,B) _clrbits((__cap_s *)A, (__cap_s *)B)
-static void _clrbits(__cap_s *a, __cap_s *b)
+static void clrbits(cap_t a, const __u32 *b, cap_flag_t set)
{
int n;
for (n = __CAP_BLKS; n--; )
- a->_blk[n] &= ~b->_blk[n];
+ a->u[n].flat[set] &= ~b[n];
}
static char const *namcmp(char const *str, char const *nam)
@@ -51,6 +52,15 @@ static char const *namcmp(char const *str, char const *nam)
return str;
}
+static void forceall(__u32 *flat, __u32 value)
+{
+ unsigned n;
+
+ for (n = __CAP_BLKS; n--; flat[n] = value);
+
+ return;
+}
+
static int lookupname(char const **strp)
{
union {
@@ -80,7 +90,6 @@ static int lookupname(char const **strp)
cap_t cap_from_text(const char *str)
{
cap_t res;
- __cap_s allones;
int n;
if (str == NULL) {
@@ -91,22 +100,24 @@ cap_t cap_from_text(const char *str)
if (!(res = cap_init()))
return NULL;
- for (n = __CAP_BLKS; n--; )
- allones._blk[n] = -1;
+
_cap_debug("%s", str);
for (;;) {
+ __u32 list[__CAP_BLKS];
char op;
int flags = 0, listed=0;
- __cap_s list = {{0}};
+
+ forceall(list, 0);
/* skip leading spaces */
while (isspace((unsigned char)*str))
str++;
if (!*str) {
- _cap_debugcap("e = ", &res->set.effective);
- _cap_debugcap("i = ", &res->set.inheritable);
- _cap_debugcap("p = ", &res->set.permitted);
+ _cap_debugcap("e = ", *res, CAP_EFFECTIVE);
+ _cap_debugcap("i = ", *res, CAP_INHERITABLE);
+ _cap_debugcap("p = ", *res, CAP_PERMITTED);
+
return res;
}
@@ -115,12 +126,12 @@ cap_t cap_from_text(const char *str)
for (;;) {
if (namcmp(str, "all")) {
str += 3;
- list = allones;
+ forceall(list, ~0);
} else {
n = lookupname(&str);
if (n == -1)
goto bad;
- list.raise_cap(n);
+ raise_cap_mask(list, n);
}
if (*str != ',')
break;
@@ -128,10 +139,11 @@ cap_t cap_from_text(const char *str)
goto bad;
}
listed = 1;
- } else if (*str == '+' || *str == '-')
+ } else if (*str == '+' || *str == '-') {
goto bad; /* require a list of capabilities */
- else
- list = allones;
+ } else {
+ forceall(list, ~0);
+ }
/* identify first operation on list of capabilities */
op = *str++;
@@ -169,28 +181,28 @@ cap_t cap_from_text(const char *str)
case '=':
case 'P': /* =+ */
case 'M': /* =- */
- clrbits(&res->set.effective, &list);
- clrbits(&res->set.inheritable, &list);
- clrbits(&res->set.permitted, &list);
- /* fall through */
+ clrbits(res, list, CAP_EFFECTIVE);
+ clrbits(res, list, CAP_PERMITTED);
+ clrbits(res, list, CAP_INHERITABLE);
if (op == 'M')
goto minus;
+ /* fall through */
case '+':
if (flags & LIBCAP_EFF)
- setbits(&res->set.effective, &list);
- if (flags & LIBCAP_INH)
- setbits(&res->set.inheritable, &list);
+ setbits(res, list, CAP_EFFECTIVE);
if (flags & LIBCAP_PER)
- setbits(&res->set.permitted, &list);
+ setbits(res, list, CAP_PERMITTED);
+ if (flags & LIBCAP_INH)
+ setbits(res, list, CAP_INHERITABLE);
break;
case '-':
minus:
- if (flags & LIBCAP_EFF)
- clrbits(&res->set.effective, &list);
- if (flags & LIBCAP_INH)
- clrbits(&res->set.inheritable, &list);
+ if (flags & LIBCAP_EFF)
+ clrbits(res, list, CAP_EFFECTIVE);
if (flags & LIBCAP_PER)
- clrbits(&res->set.permitted, &list);
+ clrbits(res, list, CAP_PERMITTED);
+ if (flags & LIBCAP_INH)
+ clrbits(res, list, CAP_INHERITABLE);
break;
}
@@ -226,12 +238,15 @@ static int getstateflags(cap_t caps, int capno)
{
int f = 0;
- if (isset_cap((__cap_s *)(&caps->set.effective),capno))
+ if (isset_cap(caps, capno, CAP_EFFECTIVE)) {
f |= LIBCAP_EFF;
- if (isset_cap((__cap_s *)(&caps->set.inheritable),capno))
- f |= LIBCAP_INH;
- if (isset_cap((__cap_s *)(&caps->set.permitted),capno))
+ }
+ if (isset_cap(caps, capno, CAP_PERMITTED)) {
f |= LIBCAP_PER;
+ }
+ if (isset_cap(caps, capno, CAP_INHERITABLE)) {
+ f |= LIBCAP_INH;
+ }
return f;
}
@@ -251,9 +266,9 @@ char *cap_to_text(cap_t caps, ssize_t *length_p)
return NULL;
}
- _cap_debugcap("e = ", &caps->set.effective);
- _cap_debugcap("i = ", &caps->set.inheritable);
- _cap_debugcap("p = ", &caps->set.permitted);
+ _cap_debugcap("e = ", *caps, CAP_EFFECTIVE);
+ _cap_debugcap("i = ", *caps, CAP_INHERITABLE);
+ _cap_debugcap("p = ", *caps, CAP_PERMITTED);
for (n = __CAP_BITS; n--; )
histo[getstateflags(caps, n)]++;
diff --git a/libcap/include/sys/capability.h b/libcap/include/sys/capability.h
index b9d2636..6dbe656 100644
--- a/libcap/include/sys/capability.h
+++ b/libcap/include/sys/capability.h
@@ -32,6 +32,7 @@ extern "C" {
#define __user
typedef unsigned int __u32;
+typedef __u32 __le32;
#include <linux/capability.h>
diff --git a/libcap/libcap.h b/libcap/libcap.h
index 20acb6b..820d61a 100644
--- a/libcap/libcap.h
+++ b/libcap/libcap.h
@@ -26,6 +26,31 @@
#include "cap_names.h"
/*
+ * Do we match the local kernel?
+ */
+
+#if !defined(_LINUX_CAPABILITY_VERSION)
+
+# error Kernel <linux/capability.h> does not support library
+# error file "libcap.h" --> fix and recompile libcap
+
+#elif (_LINUX_CAPABILITY_VERSION == 0x19980330)
+
+# warning Kernel <linux/capability.h> does not support 64-bit capabilities
+# warning and libcap is being built with no support for 64-bit capabilities
+
+# ifndef _LINUX_CAPABILITY_VERSION_1
+# define _LINUX_CAPABILITY_VERSION_1 0x19980330
+# endif
+
+#elif (_LINUX_CAPABILITY_VERSION != 0x20071026)
+
+# error Kernel <linux/capability.h> does not match library
+# error file "libcap.h" --> fix and recompile libcap
+
+#endif
+
+/*
* This is a pointer to a struct containing three consecutive
* capability sets in the order of the cap_flag_t type: the are
* effective,inheritable and permitted. This is the type that the
@@ -34,40 +59,54 @@
* to processes.
*/
+#ifndef _LINUX_CAPABILITY_U32S
+# define _LINUX_CAPABILITY_U32S 1
+#endif /* ndef _LINUX_CAPABILITY_U32S */
+
+#if defined(VFS_CAP_REVISION_MASK) && !defined(VFS_CAP_U32)
+# define VFS_CAP_U32_1 1
+# define VFS_CAP_U32 VFS_CAP_U32_1
+struct _cap_vfs_cap_data {
+ __le32 magic_etc;
+ struct {
+ __le32 permitted;
+ __le32 inheritable;
+ } data[VFS_CAP_U32_1];
+};
+# define vfs_cap_data _cap_vfs_cap_data
+#endif
+
+#ifndef CAP_TO_INDEX
+# define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */
+#endif /* ndef CAP_TO_INDEX */
+
+#ifndef CAP_TO_MASK
+# define CAP_TO_MASK(x) (1 << ((x) & 31))
+#endif /* ndef CAP_TO_MASK */
+
+#define NUMBER_OF_CAP_SETS 3 /* effective, inheritable, permitted */
+#define __CAP_BLKS (_LINUX_CAPABILITY_U32S)
+#define CAP_SET_SIZE (__CAP_BLKS * sizeof(__u32))
+
#define CAP_T_MAGIC 0xCA90D0
struct _cap_struct {
struct __user_cap_header_struct head;
- struct __user_cap_data_struct set;
+ union {
+ struct __user_cap_data_struct set;
+ __u32 flat[NUMBER_OF_CAP_SETS];
+ } u[_LINUX_CAPABILITY_U32S];
};
/* string magic for cap_free */
#define CAP_S_MAGIC 0xCA95D0
/*
- * Do we match the local kernel?
- */
-
-#if !defined(_LINUX_CAPABILITY_VERSION) || \
- (_LINUX_CAPABILITY_VERSION != 0x19980330)
-
-# error "Kernel <linux/capability.h> does not match library"
-# error "file "libcap.h" --> fix and recompile libcap"
-
-#endif
-
-/*
* kernel API cap set abstraction
*/
-#define NUMBER_OF_CAP_SETS 3 /* effective, inheritable, permitted */
-#define CAP_SET_SIZE (sizeof(struct __user_cap_data_struct)/NUMBER_OF_CAP_SETS)
-#define __CAP_BLKS (CAP_SET_SIZE/sizeof(__u32))
-typedef struct {
- __u32 _blk[__CAP_BLKS];
-} __cap_s;
-#define raise_cap(x) _blk[(x)>>5] |= (1<<((x)&31))
-#define lower_cap(x) _blk[(x)>>5] &= ~(1<<((x)&31))
-#define isset_cap(y,x) ((y)->_blk[(x)>>5] & (1<<((x)&31)))
+#define raise_cap(x,set) u[(x)>>5].flat[set] |= (1<<((x)&31))
+#define lower_cap(x,set) u[(x)>>5].flat[set] &= ~(1<<((x)&31))
+#define isset_cap(y,x,set) ((y)->u[(x)>>5].flat[set] & (1<<((x)&31)))
/*
* Private definitions for internal use by the library.
@@ -83,19 +122,25 @@ typedef struct {
#ifdef DEBUG
#include <stdio.h>
-# define _cap_debug(f, x...) { \
+# define _cap_debug(f, x...) do { \
fprintf(stderr, __FUNCTION__ "(" __FILE__ ":%d): ", __LINE__); \
fprintf(stderr, f, ## x); \
fprintf(stderr, "\n"); \
-}
-# define _cap_debugcap(s, c) \
- fprintf(stderr, __FUNCTION__ "(" __FILE__ ":%d): " s \
- "%08x\n", __LINE__, *(c))
+} while (0)
+
+# define _cap_debugcap(s, c, set) do { \
+ unsigned _cap_index; \
+ fprintf(stderr, __FUNCTION__ "(" __FILE__ ":%d): " s, __LINE__); \
+ for (_cap_index=_LINUX_CAPABILITY_U32S; _cap_index-- > 0; ) { \
+ fprintf(stderr, "%08x", (c).u[_cap_index].flat[set]); \
+ } \
+ fprintf(stderr, "\n"); \
+} while (0)
#else /* !DEBUG */
# define _cap_debug(f, x...)
-# define _cap_debugcap(s, c)
+# define _cap_debugcap(s, c, set)
#endif /* DEBUG */
diff --git a/progs/getpcaps.c b/progs/getpcaps.c
index 26dee82..8d40264 100644
--- a/progs/getpcaps.c
+++ b/progs/getpcaps.c
@@ -20,13 +20,14 @@ static void usage(void)
"usage: getcaps <pid> [<pid> ...]\n\n"
" This program displays the capabilities on the queried process(es).\n"
" The capabilities are displayed in the cap_from_text(3) format.\n\n"
-"[Copyright (c) 1997-8 Andrew G. Morgan <morgan@kernel.org>]\n"
+"[Copyright (c) 1997-8,2007 Andrew G. Morgan <morgan@kernel.org>]\n"
);
exit(1);
}
int main(int argc, char **argv)
{
+ int retval = 0;
cap_t cap_d;
if (argc < 2) {
@@ -48,7 +49,8 @@ int main(int argc, char **argv)
/* this is a non-POSIX function */
if (capgetp(pid, cap_d)) {
fprintf(stderr, "Failed to get cap's for proccess %d:"
- " (%s)\n", pid, strerror(errno));
+ " (%s) - need new libcap?\n", pid, strerror(errno));
+ retval = 1;
continue;
} else {
char *result = cap_to_text(cap_d, &length);
@@ -58,5 +60,5 @@ int main(int argc, char **argv)
}
}
- return 0;
+ return retval;
}
diff --git a/progs/setcap.c b/progs/setcap.c
index 8cd7e6a..dc13c06 100644
--- a/progs/setcap.c
+++ b/progs/setcap.c
@@ -67,21 +67,22 @@ int main(int argc, char **argv)
mycaps = cap_get_proc();
if (mycaps == NULL) {
- perror("fatal error - unable to get process capabilities");
- exit(1);
- }
- capflag = CAP_SETFCAP;
-
- /*
- * Raise the effective CAP_SETPCAP.
- */
- if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_SET) != 0) {
- perror("unable to manipulate CAP_SETFCAP - try a newer libcap?");
- exit(1);
- }
- if (cap_set_proc(mycaps) != 0) {
- perror("unable to set CAP_SETFCAP effective capability");
- exit(1);
+ fprintf(stderr, "warning - unable to get process capabilities"
+ " (old libcap?)\n");
+ } else {
+ capflag = CAP_SETFCAP;
+
+ /*
+ * Raise the effective CAP_SETPCAP.
+ */
+ if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_SET) != 0) {
+ perror("unable to manipulate CAP_SETFCAP - try a newer libcap?");
+ exit(1);
+ }
+ if (cap_set_proc(mycaps) != 0) {
+ perror("unable to set CAP_SETFCAP effective capability");
+ exit(1);
+ }
}
while (--argc > 0) {