diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2008-02-26 06:52:33 -0800 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2008-02-26 06:52:33 -0800 |
commit | 4d344bd835ba0b93930c63e57f9bf45616aae8ff (patch) | |
tree | 533cdd4a9c94935b5f66ec171bdc61b189268e42 | |
parent | 47bd77b2624b5efa155d7de9a4cb35ce3d58f0c8 (diff) | |
download | libcap-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.3 | 13 | ||||
-rw-r--r-- | libcap/cap_text.c | 78 |
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; |