17baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan/*
27aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan * Copyright (c) 1997-8,2007-8 Andrew G Morgan <morgan@kernel.org>
37baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan * Copyright (c) 1997 Andrew Main <zefram@dcs.warwick.ac.uk>
47baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan *
57baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan * This file deals with exchanging internal and textual
67baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan * representations of capability sets.
77baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan */
87baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
9159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan#define _GNU_SOURCE
10159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan#include <stdio.h>
11159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan
127baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan#define LIBCAP_PLEASE_INCLUDE_ARRAY
137baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan#include "libcap.h"
147baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
157baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan#include <ctype.h>
16907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan#include <limits.h>
177baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
187baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan/* Maximum output text length (16 per cap) */
19c2a25909b2c4d989e49cdedcac4dd52c45f0570bAndrew G. Morgan#define CAP_TEXT_SIZE    (16*__CAP_MAXBITS)
207baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
217baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan/*
227baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan * Parse a textual representation of capabilities, returning an internal
237baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan * representation.
247baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan */
257baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
2632423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan#define raise_cap_mask(flat, c)  (flat)[CAP_TO_INDEX(c)] |= CAP_TO_MASK(c)
2732423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan
283f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morganstatic void setbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks)
297baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan{
307baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    int n;
313f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    for (n = blks; n--; ) {
3232423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	a->u[n].flat[set] |= b[n];
3332423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    }
347baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan}
357baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
363f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morganstatic void clrbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks)
377baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan{
387baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    int n;
393f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    for (n = blks; n--; )
4032423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	a->u[n].flat[set] &= ~b[n];
417baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan}
427baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
437baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morganstatic char const *namcmp(char const *str, char const *nam)
447baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan{
457baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    while (*nam && tolower((unsigned char)*str) == *nam) {
467baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	str++;
477baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	nam++;
487baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    }
497baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    if (*nam || isalnum((unsigned char)*str) || *str == '_')
507baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	return NULL;
517baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    return str;
527baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan}
537baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
543f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morganstatic void forceall(__u32 *flat, __u32 value, unsigned blks)
5532423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan{
5632423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    unsigned n;
5732423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan
583f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    for (n = blks; n--; flat[n] = value);
5932423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan
6032423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    return;
6132423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan}
6232423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan
637baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morganstatic int lookupname(char const **strp)
647baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan{
65ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan    union {
66ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan	char const *constp;
67ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan	char *p;
68ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan    } str;
69ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan
70ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan    str.constp = *strp;
71ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan    if (isdigit(*str.constp)) {
72ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan	unsigned long n = strtoul(str.constp, &str.p, 0);
73c2a25909b2c4d989e49cdedcac4dd52c45f0570bAndrew G. Morgan	if (n >= __CAP_MAXBITS)
747baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    return -1;
75ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan	*strp = str.constp;
767baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	return n;
777baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    } else {
783184213774c3fb3e467c7bea080a88f6b984b4e4Andrew G. Morgan	int c;
797aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	unsigned len;
807aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan
817aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	for (len=0; (c = str.constp[len]); ++len) {
827aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	    if (!(isalpha(c) || (c == '_'))) {
837aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan		break;
847aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	    }
857aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	}
86159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan
87159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan#ifdef GPERF_DOWNCASE
88159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan	const struct __cap_token_s *token_info;
89159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan
907aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	token_info = __cap_lookup_name(str.constp, len);
917aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	if (token_info != NULL) {
927aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	    *strp = str.constp + len;
937aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	    return token_info->index;
947aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	}
957aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan#else /* ie., ndef GPERF_DOWNCASE */
967baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	char const *s;
973184213774c3fb3e467c7bea080a88f6b984b4e4Andrew G. Morgan	unsigned n;
98159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan
997baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	for (n = __CAP_BITS; n--; )
100ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan	    if (_cap_names[n] && (s = namcmp(str.constp, _cap_names[n]))) {
1017baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		*strp = s;
1027baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		return n;
1037baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    }
1047aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan#endif /* def GPERF_DOWNCASE */
1057aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan
1067aff2edf61f96087e7ac47def97acb638bb7bca2Andrew G. Morgan	return -1;   	/* No definition available */
1077baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    }
1087baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan}
1097baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
1107baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgancap_t cap_from_text(const char *str)
1117baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan{
1127baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    cap_t res;
1137baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    int n;
1143f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    unsigned cap_blks;
1157baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
1167baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    if (str == NULL) {
1177baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	_cap_debug("bad argument");
1187baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	errno = EINVAL;
1197baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	return NULL;
1207baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    }
1217baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
1227baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    if (!(res = cap_init()))
1237baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	return NULL;
12432423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan
1253f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    switch (res->head.version) {
1263f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    case _LINUX_CAPABILITY_VERSION_1:
1273f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	cap_blks = _LINUX_CAPABILITY_U32S_1;
1283f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	break;
1293f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    case _LINUX_CAPABILITY_VERSION_2:
1303f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	cap_blks = _LINUX_CAPABILITY_U32S_2;
1313f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	break;
132d62769b6fc69244bd9922b018787d8bb7e332118Andrew G. Morgan    case _LINUX_CAPABILITY_VERSION_3:
133d62769b6fc69244bd9922b018787d8bb7e332118Andrew G. Morgan	cap_blks = _LINUX_CAPABILITY_U32S_3;
134d62769b6fc69244bd9922b018787d8bb7e332118Andrew G. Morgan	break;
1353f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    default:
1363f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	errno = EINVAL;
1373f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	return NULL;
1383f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    }
1393f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan
1407baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    _cap_debug("%s", str);
1417baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
1427baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    for (;;) {
14332423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	__u32 list[__CAP_BLKS];
1447baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	char op;
1457baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	int flags = 0, listed=0;
14632423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan
1473f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	forceall(list, 0, __CAP_BLKS);
1487baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
1497baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	/* skip leading spaces */
1507baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	while (isspace((unsigned char)*str))
1517baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    str++;
1527baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	if (!*str) {
15332423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	    _cap_debugcap("e = ", *res, CAP_EFFECTIVE);
15432423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	    _cap_debugcap("i = ", *res, CAP_INHERITABLE);
15532423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	    _cap_debugcap("p = ", *res, CAP_PERMITTED);
15632423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan
1577baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    return res;
1587baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	}
1597baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
1607baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	/* identify caps specified by this clause */
1617baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	if (isalnum((unsigned char)*str) || *str == '_') {
1627baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    for (;;) {
1637baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (namcmp(str, "all")) {
1647baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    str += 3;
1653f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		    forceall(list, ~0, cap_blks);
1667baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		} else {
1677baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    n = lookupname(&str);
1687baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    if (n == -1)
1697baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan			goto bad;
17032423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan		    raise_cap_mask(list, n);
1717baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		}
1727baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (*str != ',')
1737baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    break;
1747baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (!isalnum((unsigned char)*++str) && *str != '_')
1757baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    goto bad;
1767baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    }
1777baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    listed = 1;
17832423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	} else if (*str == '+' || *str == '-') {
1797baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    goto bad;                    /* require a list of capabilities */
18032423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	} else {
1813f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	    forceall(list, ~0, cap_blks);
18232423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	}
1837baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
1847baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	/* identify first operation on list of capabilities */
1857baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	op = *str++;
1867baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	if (op == '=' && (*str == '+' || *str == '-')) {
1877baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    if (!listed)
1887baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		goto bad;
1897baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    op = (*str++ == '+' ? 'P':'M'); /* skip '=' and take next op */
1907baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	} else if (op != '+' && op != '-' && op != '=')
1917baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    goto bad;
1927baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
1937baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	/* cycle through list of actions */
1947baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	do {
1957baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    _cap_debug("next char = `%c'", *str);
1967baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    if (*str && !isspace(*str)) {
1977baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		switch (*str++) {    /* Effective, Inheritable, Permitted */
1987baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		case 'e':
1997baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    flags |= LIBCAP_EFF;
2007baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    break;
2017baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		case 'i':
2027baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    flags |= LIBCAP_INH;
2037baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    break;
2047baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		case 'p':
2057baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    flags |= LIBCAP_PER;
2067baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    break;
2077baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		default:
2087baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    goto bad;
2097baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		}
2107baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    } else if (op != '=') {
2117baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		_cap_debug("only '=' can be followed by space");
2127baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		goto bad;
2137baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    }
2147baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
2157baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    _cap_debug("how to read?");
2167baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    switch (op) {               /* how do we interpret the caps? */
2177baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    case '=':
2187baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    case 'P':                                              /* =+ */
2197baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    case 'M':                                              /* =- */
2203f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		clrbits(res, list, CAP_EFFECTIVE, cap_blks);
2213f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		clrbits(res, list, CAP_PERMITTED, cap_blks);
2223f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		clrbits(res, list, CAP_INHERITABLE, cap_blks);
2237baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (op == 'M')
2247baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    goto minus;
22532423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan		/* fall through */
2267baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    case '+':
2277baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (flags & LIBCAP_EFF)
2283f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		    setbits(res, list, CAP_EFFECTIVE, cap_blks);
2297baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (flags & LIBCAP_PER)
2303f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		    setbits(res, list, CAP_PERMITTED, cap_blks);
23132423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan		if (flags & LIBCAP_INH)
2323f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		    setbits(res, list, CAP_INHERITABLE, cap_blks);
2337baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		break;
2347baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    case '-':
2357baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    minus:
23632423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan		if (flags & LIBCAP_EFF)
2373f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		    clrbits(res, list, CAP_EFFECTIVE, cap_blks);
2387baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (flags & LIBCAP_PER)
2393f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		    clrbits(res, list, CAP_PERMITTED, cap_blks);
24032423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan		if (flags & LIBCAP_INH)
2413f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		    clrbits(res, list, CAP_INHERITABLE, cap_blks);
2427baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		break;
2437baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    }
2447baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
2457baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    /* new directive? */
2467baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    if (*str == '+' || *str == '-') {
2477baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (!listed) {
2487baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    _cap_debug("for + & - must list capabilities");
2497baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    goto bad;
2507baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		}
2517baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		flags = 0;                       /* reset the flags */
2527baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		op = *str++;
2537baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (!isalpha(*str))
2547baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    goto bad;
2557baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    }
2567baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	} while (*str && !isspace(*str));
2577baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	_cap_debug("next clause");
2587baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    }
2597baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
2607baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morganbad:
261ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan    cap_free(res);
262ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan    res = NULL;
2637baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    errno = EINVAL;
264ec25bd9b420ab62bcc3ec709f467eb43d434b66dAndrew Morgan    return res;
2657baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan}
2667baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
2677baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan/*
268907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan * lookup a capability name and return its numerical value
269907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan */
270907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morganint cap_from_name(const char *name, cap_value_t *value_p)
271907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan{
272907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan    int n;
273907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan
274597369a007f20080e13ffbe3a4dfed38897c7edcAndrew G. Morgan    if (((n = lookupname(&name)) >= 0) && (value_p != NULL)) {
275907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan	*value_p = (unsigned) n;
276907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan    }
277907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan    return -(n < 0);
278907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan}
279907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan
280907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan/*
281907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan * Convert a single capability index number into a string representation
282907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan */
283907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morganchar *cap_to_name(cap_value_t cap)
284907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan{
285907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan    if ((cap < 0) || (cap >= __CAP_BITS)) {
286907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan#if UINT_MAX != 4294967295U
287907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan# error Recompile with correctly sized numeric array
288907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan#endif
289159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan	char *tmp, *result;
290907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan
2913184213774c3fb3e467c7bea080a88f6b984b4e4Andrew G. Morgan	asprintf(&tmp, "%u", cap);
292159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan	result = _libcap_strdup(tmp);
293159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan	free(tmp);
294159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan
295159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan	return result;
296907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan    } else {
297907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan	return _libcap_strdup(_cap_names[cap]);
298907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan    }
299907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan}
300907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan
301907393e8d611fc887440d77335bc87adc0bed0bdAndrew G. Morgan/*
3027baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan * Convert an internal representation to a textual one. The textual
3037baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan * representation is stored in static memory. It will be overwritten
3047baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan * on the next occasion that this function is called.
3057baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan */
3067baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
3077baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morganstatic int getstateflags(cap_t caps, int capno)
3087baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan{
3097baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    int f = 0;
3107baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
31132423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    if (isset_cap(caps, capno, CAP_EFFECTIVE)) {
3127baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	f |= LIBCAP_EFF;
31332423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    }
31432423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    if (isset_cap(caps, capno, CAP_PERMITTED)) {
3157baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	f |= LIBCAP_PER;
31632423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    }
31732423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    if (isset_cap(caps, capno, CAP_INHERITABLE)) {
31832423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan	f |= LIBCAP_INH;
31932423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    }
3207baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
3217baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    return f;
3227baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan}
3237baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
3247baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan#define CAP_TEXT_BUFFER_ZONE 100
3257baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
3267baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morganchar *cap_to_text(cap_t caps, ssize_t *length_p)
3277baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan{
3283f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    char buf[CAP_TEXT_SIZE+CAP_TEXT_BUFFER_ZONE];
3297baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    char *p;
3303f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    int histo[8];
331c2a25909b2c4d989e49cdedcac4dd52c45f0570bAndrew G. Morgan    int m, t;
332c2a25909b2c4d989e49cdedcac4dd52c45f0570bAndrew G. Morgan    unsigned n;
3333f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    unsigned cap_maxbits, cap_blks;
3347baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
3357baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    /* Check arguments */
3362153ffce3a55344869504792a7aaf365990cc3f0Andrew Morgan    if (!good_cap_t(caps)) {
3377baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	errno = EINVAL;
3387baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	return NULL;
3397baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    }
3407baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
3413f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    switch (caps->head.version) {
3423f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    case _LINUX_CAPABILITY_VERSION_1:
3433f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	cap_blks = _LINUX_CAPABILITY_U32S_1;
3443f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	break;
3453f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    case _LINUX_CAPABILITY_VERSION_2:
3463f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	cap_blks = _LINUX_CAPABILITY_U32S_2;
3473f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	break;
348d62769b6fc69244bd9922b018787d8bb7e332118Andrew G. Morgan    case _LINUX_CAPABILITY_VERSION_3:
349d62769b6fc69244bd9922b018787d8bb7e332118Andrew G. Morgan	cap_blks = _LINUX_CAPABILITY_U32S_3;
350d62769b6fc69244bd9922b018787d8bb7e332118Andrew G. Morgan	break;
3513f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    default:
3523f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	errno = EINVAL;
3533f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	return NULL;
3543f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    }
3553f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan
3563f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    cap_maxbits = 32 * cap_blks;
3573f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan
35832423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    _cap_debugcap("e = ", *caps, CAP_EFFECTIVE);
35932423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    _cap_debugcap("i = ", *caps, CAP_INHERITABLE);
36032423d46c83c639c2df7db7ee74b8ec7be2b1234Andrew Morgan    _cap_debugcap("p = ", *caps, CAP_PERMITTED);
3617baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
3623f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan    memset(histo, 0, sizeof(histo));
3633f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan
364e482cc22ad687f50882f0029ed4b9adebb01911cAndrew G. Morgan    /* default prevailing state to the upper - unnamed bits */
365e482cc22ad687f50882f0029ed4b9adebb01911cAndrew G. Morgan    for (n = cap_maxbits-1; n > __CAP_BITS; n--)
3667baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	histo[getstateflags(caps, n)]++;
3677baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
368d718c084e9f95b793d16a66788670610a37774f9Andrew G. Morgan    /* find which combination of capability sets shares the most bits
369d718c084e9f95b793d16a66788670610a37774f9Andrew G. Morgan       we bias to preferring non-set (m=0) with the >= 0 test. Failing
370d718c084e9f95b793d16a66788670610a37774f9Andrew G. Morgan       to do this causes strange things to happen with older systems
371d718c084e9f95b793d16a66788670610a37774f9Andrew G. Morgan       that don't know about bits 32+. */
3727baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    for (m=t=7; t--; )
373d718c084e9f95b793d16a66788670610a37774f9Andrew G. Morgan	if (histo[t] >= histo[m])
3747baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    m = t;
3757baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
376e482cc22ad687f50882f0029ed4b9adebb01911cAndrew G. Morgan    /* capture remaining bits - selecting m from only the unnamed bits,
377e482cc22ad687f50882f0029ed4b9adebb01911cAndrew G. Morgan       we maximize the likelihood that we won't see numeric capability
378e482cc22ad687f50882f0029ed4b9adebb01911cAndrew G. Morgan       values in the text output. */
379e482cc22ad687f50882f0029ed4b9adebb01911cAndrew G. Morgan    while (n--)
380e482cc22ad687f50882f0029ed4b9adebb01911cAndrew G. Morgan	histo[getstateflags(caps, n)]++;
381e482cc22ad687f50882f0029ed4b9adebb01911cAndrew G. Morgan
3827baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    /* blank is not a valid capability set */
3837baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    p = sprintf(buf, "=%s%s%s",
3847baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		(m & LIBCAP_EFF) ? "e" : "",
3857baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		(m & LIBCAP_INH) ? "i" : "",
3867baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		(m & LIBCAP_PER) ? "p" : "" ) + buf;
3877baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
3887baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    for (t = 8; t--; )
3897baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	if (t != m && histo[t]) {
3907baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    *p++ = ' ';
3913f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan	    for (n = 0; n < cap_maxbits; n++)
3927baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		if (getstateflags(caps, n) == t) {
393159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan		    char *this_cap_name;
394159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan
395159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan		    this_cap_name = cap_to_name(n);
3963f7da3c2259741354f4e55105c466ae1443a0490Andrew G. Morgan		    if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
397159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan			cap_free(this_cap_name);
3987baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan			errno = ERANGE;
3997baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan			return NULL;
4007baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		    }
401159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan		    p += sprintf(p, "%s,", this_cap_name);
402159fc80362a68a54ca72d1a0419975ac76333d4bAndrew G. Morgan		    cap_free(this_cap_name);
4037baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		}
4047baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    p--;
4057baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    n = t & ~m;
4067baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    if (n)
4077baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		p += sprintf(p, "+%s%s%s",
4087baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan			     (n & LIBCAP_EFF) ? "e" : "",
4097baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan			     (n & LIBCAP_INH) ? "i" : "",
4107baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan			     (n & LIBCAP_PER) ? "p" : "");
4117baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    n = ~t & m;
4127baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    if (n)
4137baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		p += sprintf(p, "-%s%s%s",
4147baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan			     (n & LIBCAP_EFF) ? "e" : "",
4157baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan			     (n & LIBCAP_INH) ? "i" : "",
4167baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan			     (n & LIBCAP_PER) ? "p" : "");
4177baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    if (p - buf > CAP_TEXT_SIZE) {
4187baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		errno = ERANGE;
4197baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan		return NULL;
4207baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	    }
4217baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan	}
4227baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan
4237baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan    _cap_debug("%s", buf);
4242153ffce3a55344869504792a7aaf365990cc3f0Andrew Morgan    if (length_p) {
4252153ffce3a55344869504792a7aaf365990cc3f0Andrew Morgan	*length_p = p - buf;
4262153ffce3a55344869504792a7aaf365990cc3f0Andrew Morgan    }
4272153ffce3a55344869504792a7aaf365990cc3f0Andrew Morgan
428f9c44c45c23630bcf24135d7972a298aad5949eaAndrew Morgan    return (_libcap_strdup(buf));
4297baf3be8302d9a7ba63c8c57131ecbc3fbd6d3ebAndrew Morgan}
430