aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2008-02-26 06:52:33 -0800
committerAndrew G. Morgan <morgan@kernel.org>2008-02-26 06:52:33 -0800
commit4d344bd835ba0b93930c63e57f9bf45616aae8ff (patch)
tree533cdd4a9c94935b5f66ec171bdc61b189268e42
parent47bd77b2624b5efa155d7de9a4cb35ce3d58f0c8 (diff)
downloadlibcap-4d344bd835ba0b93930c63e57f9bf45616aae8ff.tar.gz
Add support for Kohei KaiGai's /sys/kernel/capability/ files.
This change adds support for checking for new capabilities in the /sys/kernel/capability/{codes,names}/* files when the library wasn't compiled with the latest capabilities. Also update documentation for cap_from_text.3 to be more explicit about how to free a libcap allocated string. (Bug reported by Serge.) Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r--doc/cap_from_text.313
-rw-r--r--libcap/cap_text.c78
2 files changed, 71 insertions, 20 deletions
diff --git a/doc/cap_from_text.3 b/doc/cap_from_text.3
index e4a3e76..d27dfcb 100644
--- a/doc/cap_from_text.3
+++ b/doc/cap_from_text.3
@@ -24,9 +24,10 @@ functions in working storage. The textual representation is a structured,
human-readable, string suitable for display.
.PP
.B cap_from_text
-allocates and initializes a capability state in working storage. It then
-sets the contents of this newly-created capability state to the state
-represented by human-readable, null terminated character string pointed to by
+allocates and initializes a capability state in working storage. It
+then sets the contents of this newly-created capability state to the
+state represented by a human-readable, nul terminated, character
+string pointed to by
.IR buf_p .
It returns a pointer to the newly created capability state. The
caller should free any releasable memory, when the capability state in working
@@ -52,7 +53,7 @@ the string. If the pointer
is not
.BR NULL ,
the function shall also return the full length of the string (not including
-the null terminator) in the location pointed to by
+the nul terminator) in the location pointed to by
.IR len_p .
The capability state in working storage, identified by
.IR cap_p ,
@@ -60,9 +61,7 @@ is completely represented in the character string. The caller should
free any releasable memory, when the capability state in working
storage is no longer required, by calling
.B cap_free
-with
-.B cap_p
-as an argument.
+with the returned string pointer as an argument.
.PP
.B cap_from_name
converts a text representation of a capability, such as "cap_chown",
diff --git a/libcap/cap_text.c b/libcap/cap_text.c
index 6874153..6dfc15b 100644
--- a/libcap/cap_text.c
+++ b/libcap/cap_text.c
@@ -6,12 +6,19 @@
* representations of capability sets.
*/
+#define _GNU_SOURCE
+#include <stdio.h>
+
#define LIBCAP_PLEASE_INCLUDE_ARRAY
#include "libcap.h"
#include <ctype.h>
-#include <stdio.h>
#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define SYS_DIR_ROOT_NAMES "/sys/kernel/capability/names"
+#define SYS_DIR_ROOT_CODES "/sys/kernel/capability/codes"
/* Maximum output text length (16 per cap) */
#define CAP_TEXT_SIZE (16*__CAP_MAXBITS)
@@ -77,9 +84,9 @@ static int lookupname(char const **strp)
*strp = str.constp;
return n;
} else {
-#ifdef GPERF_DOWNCASE
- const struct __cap_token_s *token_info;
- int c;
+ int fd;
+ char *tmp;
+ int c, n;
unsigned len;
for (len=0; (c = str.constp[len]); ++len) {
@@ -87,6 +94,10 @@ static int lookupname(char const **strp)
break;
}
}
+
+#ifdef GPERF_DOWNCASE
+ const struct __cap_token_s *token_info;
+
token_info = __cap_lookup_name(str.constp, len);
if (token_info != NULL) {
*strp = str.constp + len;
@@ -94,7 +105,7 @@ static int lookupname(char const **strp)
}
#else /* ie., ndef GPERF_DOWNCASE */
char const *s;
- int n;
+
for (n = __CAP_BITS; n--; )
if (_cap_names[n] && (s = namcmp(str.constp, _cap_names[n]))) {
*strp = s;
@@ -102,6 +113,25 @@ static int lookupname(char const **strp)
}
#endif /* def GPERF_DOWNCASE */
+ asprintf(&tmp, SYS_DIR_ROOT_NAMES "/%s", str.constp);
+ str.constp += len;
+ tmp[sizeof(SYS_DIR_ROOT_NAMES) + len] = '\0';
+
+ fd = open(tmp, O_RDONLY);
+ free(tmp);
+
+ if (fd >= 0) {
+ char ref[10];
+
+ len = read(fd, ref, 9);
+ close(fd);
+ if (len > 0) {
+ ref[len] = '\0';
+ n = strtoul(ref, NULL, 10);
+ *strp = str.constp;
+ return n;
+ }
+ }
return -1; /* No definition available */
}
}
@@ -269,10 +299,29 @@ char *cap_to_name(cap_value_t cap)
#if UINT_MAX != 4294967295U
# error Recompile with correctly sized numeric array
#endif
- char numeric[11];
+ char *tmp, *result;
+ int fd, len;
+
+ asprintf(&tmp, SYS_DIR_ROOT_CODES "/%u", cap);
+ fd = open(tmp, O_RDONLY);
+
+ if (fd >= 0) {
+ len = read(fd, tmp, sizeof(SYS_DIR_ROOT_CODES));
+ close(fd);
+ if (len > 0) {
+ tmp[len-1] = '\0';
+ } else {
+ goto default_to_numeric;
+ }
+ } else {
+ default_to_numeric:
+ sprintf(tmp, "%u", cap);
+ }
- sprintf(numeric, "%u", cap);
- return _libcap_strdup(numeric);
+ result = _libcap_strdup(tmp);
+ free(tmp);
+
+ return result;
} else {
return _libcap_strdup(_cap_names[cap]);
}
@@ -339,14 +388,17 @@ char *cap_to_text(cap_t caps, ssize_t *length_p)
*p++ = ' ';
for (n = 0; n < __CAP_MAXBITS; n++)
if (getstateflags(caps, n) == t) {
- if (n < __CAP_BITS)
- p += sprintf(p, "%s,", _cap_names[n]);
- else
- p += sprintf(p, "%u,", n);
- if (p - buf > CAP_TEXT_SIZE) {
+ char *this_cap_name;
+
+ this_cap_name = cap_to_name(n);
+ if ((strlen(this_cap_name) + (p - buf))
+ > CAP_TEXT_SIZE) {
+ cap_free(this_cap_name);
errno = ERANGE;
return NULL;
}
+ p += sprintf(p, "%s,", this_cap_name);
+ cap_free(this_cap_name);
}
p--;
n = t & ~m;