xref: /aosp_15_r20/external/libcap/libcap/cap_text.c (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
1*2810ac1bSKiyoung Kim /*
2*2810ac1bSKiyoung Kim  * Copyright (c) 1997-8,2007-8,2019,2021 Andrew G Morgan <[email protected]>
3*2810ac1bSKiyoung Kim  * Copyright (c) 1997 Andrew Main <[email protected]>
4*2810ac1bSKiyoung Kim  *
5*2810ac1bSKiyoung Kim  * This file deals with exchanging internal and textual
6*2810ac1bSKiyoung Kim  * representations of capability sets.
7*2810ac1bSKiyoung Kim  */
8*2810ac1bSKiyoung Kim 
9*2810ac1bSKiyoung Kim #ifndef _GNU_SOURCE
10*2810ac1bSKiyoung Kim #define _GNU_SOURCE
11*2810ac1bSKiyoung Kim #endif
12*2810ac1bSKiyoung Kim 
13*2810ac1bSKiyoung Kim #include <stdio.h>
14*2810ac1bSKiyoung Kim 
15*2810ac1bSKiyoung Kim #define LIBCAP_PLEASE_INCLUDE_ARRAY
16*2810ac1bSKiyoung Kim #include "libcap.h"
17*2810ac1bSKiyoung Kim 
18*2810ac1bSKiyoung Kim static char const *_cap_names[__CAP_BITS] = LIBCAP_CAP_NAMES;
19*2810ac1bSKiyoung Kim 
20*2810ac1bSKiyoung Kim #include <ctype.h>
21*2810ac1bSKiyoung Kim #include <limits.h>
22*2810ac1bSKiyoung Kim 
23*2810ac1bSKiyoung Kim #ifdef INCLUDE_GPERF_OUTPUT
24*2810ac1bSKiyoung Kim /* we need to include it after #define _GNU_SOURCE is set */
25*2810ac1bSKiyoung Kim #include INCLUDE_GPERF_OUTPUT
26*2810ac1bSKiyoung Kim #endif
27*2810ac1bSKiyoung Kim 
28*2810ac1bSKiyoung Kim /* Maximum output text length */
29*2810ac1bSKiyoung Kim #define CAP_TEXT_SIZE    (__CAP_NAME_SIZE * __CAP_MAXBITS)
30*2810ac1bSKiyoung Kim 
31*2810ac1bSKiyoung Kim /*
32*2810ac1bSKiyoung Kim  * Parse a textual representation of capabilities, returning an internal
33*2810ac1bSKiyoung Kim  * representation.
34*2810ac1bSKiyoung Kim  */
35*2810ac1bSKiyoung Kim 
36*2810ac1bSKiyoung Kim #define raise_cap_mask(flat, c)  (flat)[CAP_TO_INDEX(c)] |= CAP_TO_MASK(c)
37*2810ac1bSKiyoung Kim 
setbits(cap_t a,const __u32 * b,cap_flag_t set,unsigned blks)38*2810ac1bSKiyoung Kim static void setbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks)
39*2810ac1bSKiyoung Kim {
40*2810ac1bSKiyoung Kim     int n;
41*2810ac1bSKiyoung Kim     for (n = blks; n--; ) {
42*2810ac1bSKiyoung Kim 	a->u[n].flat[set] |= b[n];
43*2810ac1bSKiyoung Kim     }
44*2810ac1bSKiyoung Kim }
45*2810ac1bSKiyoung Kim 
clrbits(cap_t a,const __u32 * b,cap_flag_t set,unsigned blks)46*2810ac1bSKiyoung Kim static void clrbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks)
47*2810ac1bSKiyoung Kim {
48*2810ac1bSKiyoung Kim     int n;
49*2810ac1bSKiyoung Kim     for (n = blks; n--; )
50*2810ac1bSKiyoung Kim 	a->u[n].flat[set] &= ~b[n];
51*2810ac1bSKiyoung Kim }
52*2810ac1bSKiyoung Kim 
namcmp(char const * str,char const * nam)53*2810ac1bSKiyoung Kim static char const *namcmp(char const *str, char const *nam)
54*2810ac1bSKiyoung Kim {
55*2810ac1bSKiyoung Kim     while (*nam && tolower((unsigned char)*str) == *nam) {
56*2810ac1bSKiyoung Kim 	str++;
57*2810ac1bSKiyoung Kim 	nam++;
58*2810ac1bSKiyoung Kim     }
59*2810ac1bSKiyoung Kim     if (*nam || isalnum((unsigned char)*str) || *str == '_')
60*2810ac1bSKiyoung Kim 	return NULL;
61*2810ac1bSKiyoung Kim     return str;
62*2810ac1bSKiyoung Kim }
63*2810ac1bSKiyoung Kim 
64*2810ac1bSKiyoung Kim /*
65*2810ac1bSKiyoung Kim  * forceall forces all of the kernel named capabilities to be assigned
66*2810ac1bSKiyoung Kim  * the masked value, and zeroed otherwise. Note, if the kernel is ahead
67*2810ac1bSKiyoung Kim  * of libcap, the upper bits will be referred to by number.
68*2810ac1bSKiyoung Kim  */
forceall(__u32 * flat,__u32 value,unsigned blks)69*2810ac1bSKiyoung Kim static void forceall(__u32 *flat, __u32 value, unsigned blks)
70*2810ac1bSKiyoung Kim {
71*2810ac1bSKiyoung Kim     unsigned n;
72*2810ac1bSKiyoung Kim     cap_value_t cmb = cap_max_bits();
73*2810ac1bSKiyoung Kim     for (n = blks; n--; ) {
74*2810ac1bSKiyoung Kim 	unsigned base = 32*n;
75*2810ac1bSKiyoung Kim 	__u32 mask = 0;
76*2810ac1bSKiyoung Kim 	if (cmb >= base + 32) {
77*2810ac1bSKiyoung Kim 	    mask = ~0;
78*2810ac1bSKiyoung Kim 	} else if (cmb > base) {
79*2810ac1bSKiyoung Kim 	    mask = (unsigned) ((1ULL << (cmb % 32)) - 1);
80*2810ac1bSKiyoung Kim 	}
81*2810ac1bSKiyoung Kim 	flat[n] = value & mask;
82*2810ac1bSKiyoung Kim     }
83*2810ac1bSKiyoung Kim 
84*2810ac1bSKiyoung Kim     return;
85*2810ac1bSKiyoung Kim }
86*2810ac1bSKiyoung Kim 
lookupname(char const ** strp)87*2810ac1bSKiyoung Kim static int lookupname(char const **strp)
88*2810ac1bSKiyoung Kim {
89*2810ac1bSKiyoung Kim     union {
90*2810ac1bSKiyoung Kim 	char const *constp;
91*2810ac1bSKiyoung Kim 	char *p;
92*2810ac1bSKiyoung Kim     } str;
93*2810ac1bSKiyoung Kim 
94*2810ac1bSKiyoung Kim     str.constp = *strp;
95*2810ac1bSKiyoung Kim     if (isdigit(*str.constp)) {
96*2810ac1bSKiyoung Kim 	unsigned long n = strtoul(str.constp, &str.p, 0);
97*2810ac1bSKiyoung Kim 	if (n >= __CAP_MAXBITS)
98*2810ac1bSKiyoung Kim 	    return -1;
99*2810ac1bSKiyoung Kim 	*strp = str.constp;
100*2810ac1bSKiyoung Kim 	return n;
101*2810ac1bSKiyoung Kim     } else {
102*2810ac1bSKiyoung Kim 	int c;
103*2810ac1bSKiyoung Kim 	size_t len;
104*2810ac1bSKiyoung Kim 
105*2810ac1bSKiyoung Kim 	for (len=0; (c = str.constp[len]); ++len) {
106*2810ac1bSKiyoung Kim 	    if (!(isalpha(c) || (c == '_'))) {
107*2810ac1bSKiyoung Kim 		break;
108*2810ac1bSKiyoung Kim 	    }
109*2810ac1bSKiyoung Kim 	}
110*2810ac1bSKiyoung Kim 
111*2810ac1bSKiyoung Kim #ifdef GPERF_DOWNCASE
112*2810ac1bSKiyoung Kim 	const struct __cap_token_s *token_info;
113*2810ac1bSKiyoung Kim 
114*2810ac1bSKiyoung Kim 	token_info = __cap_lookup_name(str.constp, len);
115*2810ac1bSKiyoung Kim 	if (token_info != NULL) {
116*2810ac1bSKiyoung Kim 	    *strp = str.constp + len;
117*2810ac1bSKiyoung Kim 	    return token_info->index;
118*2810ac1bSKiyoung Kim 	}
119*2810ac1bSKiyoung Kim #else /* ie., ndef GPERF_DOWNCASE */
120*2810ac1bSKiyoung Kim 	char const *s;
121*2810ac1bSKiyoung Kim 	unsigned n = cap_max_bits();
122*2810ac1bSKiyoung Kim 	if (n > __CAP_BITS) {
123*2810ac1bSKiyoung Kim 	    n = __CAP_BITS;
124*2810ac1bSKiyoung Kim 	}
125*2810ac1bSKiyoung Kim 	while (n--) {
126*2810ac1bSKiyoung Kim 	    if (_cap_names[n] && (s = namcmp(str.constp, _cap_names[n]))) {
127*2810ac1bSKiyoung Kim 		*strp = s;
128*2810ac1bSKiyoung Kim 		return n;
129*2810ac1bSKiyoung Kim 	    }
130*2810ac1bSKiyoung Kim 	}
131*2810ac1bSKiyoung Kim #endif /* def GPERF_DOWNCASE */
132*2810ac1bSKiyoung Kim 
133*2810ac1bSKiyoung Kim 	return -1;   	/* No definition available */
134*2810ac1bSKiyoung Kim     }
135*2810ac1bSKiyoung Kim }
136*2810ac1bSKiyoung Kim 
cap_from_text(const char * str)137*2810ac1bSKiyoung Kim cap_t cap_from_text(const char *str)
138*2810ac1bSKiyoung Kim {
139*2810ac1bSKiyoung Kim     cap_t res;
140*2810ac1bSKiyoung Kim     int n;
141*2810ac1bSKiyoung Kim     unsigned cap_blks;
142*2810ac1bSKiyoung Kim 
143*2810ac1bSKiyoung Kim     if (str == NULL) {
144*2810ac1bSKiyoung Kim 	_cap_debug("bad argument");
145*2810ac1bSKiyoung Kim 	errno = EINVAL;
146*2810ac1bSKiyoung Kim 	return NULL;
147*2810ac1bSKiyoung Kim     }
148*2810ac1bSKiyoung Kim 
149*2810ac1bSKiyoung Kim     if (!(res = cap_init()))
150*2810ac1bSKiyoung Kim 	return NULL;
151*2810ac1bSKiyoung Kim 
152*2810ac1bSKiyoung Kim     switch (res->head.version) {
153*2810ac1bSKiyoung Kim     case _LINUX_CAPABILITY_VERSION_1:
154*2810ac1bSKiyoung Kim 	cap_blks = _LINUX_CAPABILITY_U32S_1;
155*2810ac1bSKiyoung Kim 	break;
156*2810ac1bSKiyoung Kim     case _LINUX_CAPABILITY_VERSION_2:
157*2810ac1bSKiyoung Kim 	cap_blks = _LINUX_CAPABILITY_U32S_2;
158*2810ac1bSKiyoung Kim 	break;
159*2810ac1bSKiyoung Kim     case _LINUX_CAPABILITY_VERSION_3:
160*2810ac1bSKiyoung Kim 	cap_blks = _LINUX_CAPABILITY_U32S_3;
161*2810ac1bSKiyoung Kim 	break;
162*2810ac1bSKiyoung Kim     default:
163*2810ac1bSKiyoung Kim 	cap_free(res);
164*2810ac1bSKiyoung Kim 	errno = EINVAL;
165*2810ac1bSKiyoung Kim 	return NULL;
166*2810ac1bSKiyoung Kim     }
167*2810ac1bSKiyoung Kim 
168*2810ac1bSKiyoung Kim     _cap_debug("%s", str);
169*2810ac1bSKiyoung Kim 
170*2810ac1bSKiyoung Kim     for (;;) {
171*2810ac1bSKiyoung Kim 	__u32 list[__CAP_BLKS];
172*2810ac1bSKiyoung Kim 	char op;
173*2810ac1bSKiyoung Kim 	int flags = 0, listed=0;
174*2810ac1bSKiyoung Kim 
175*2810ac1bSKiyoung Kim 	memset(list, 0, sizeof(__u32)*__CAP_BLKS);
176*2810ac1bSKiyoung Kim 
177*2810ac1bSKiyoung Kim 	/* skip leading spaces */
178*2810ac1bSKiyoung Kim 	while (isspace((unsigned char)*str))
179*2810ac1bSKiyoung Kim 	    str++;
180*2810ac1bSKiyoung Kim 	if (!*str) {
181*2810ac1bSKiyoung Kim 	    _cap_debugcap("e = ", *res, CAP_EFFECTIVE);
182*2810ac1bSKiyoung Kim 	    _cap_debugcap("i = ", *res, CAP_INHERITABLE);
183*2810ac1bSKiyoung Kim 	    _cap_debugcap("p = ", *res, CAP_PERMITTED);
184*2810ac1bSKiyoung Kim 
185*2810ac1bSKiyoung Kim 	    return res;
186*2810ac1bSKiyoung Kim 	}
187*2810ac1bSKiyoung Kim 
188*2810ac1bSKiyoung Kim 	/* identify caps specified by this clause */
189*2810ac1bSKiyoung Kim 	if (isalnum((unsigned char)*str) || *str == '_') {
190*2810ac1bSKiyoung Kim 	    for (;;) {
191*2810ac1bSKiyoung Kim 		if (namcmp(str, "all")) {
192*2810ac1bSKiyoung Kim 		    str += 3;
193*2810ac1bSKiyoung Kim 		    forceall(list, ~0, cap_blks);
194*2810ac1bSKiyoung Kim 		} else {
195*2810ac1bSKiyoung Kim 		    n = lookupname(&str);
196*2810ac1bSKiyoung Kim 		    if (n == -1)
197*2810ac1bSKiyoung Kim 			goto bad;
198*2810ac1bSKiyoung Kim 		    raise_cap_mask(list, n);
199*2810ac1bSKiyoung Kim 		}
200*2810ac1bSKiyoung Kim 		if (*str != ',')
201*2810ac1bSKiyoung Kim 		    break;
202*2810ac1bSKiyoung Kim 		if (!isalnum((unsigned char)*++str) && *str != '_')
203*2810ac1bSKiyoung Kim 		    goto bad;
204*2810ac1bSKiyoung Kim 	    }
205*2810ac1bSKiyoung Kim 	    listed = 1;
206*2810ac1bSKiyoung Kim 	} else if (*str == '+' || *str == '-') {
207*2810ac1bSKiyoung Kim 	    goto bad;                    /* require a list of capabilities */
208*2810ac1bSKiyoung Kim 	} else {
209*2810ac1bSKiyoung Kim 	    forceall(list, ~0, cap_blks);
210*2810ac1bSKiyoung Kim 	}
211*2810ac1bSKiyoung Kim 
212*2810ac1bSKiyoung Kim 	/* identify first operation on list of capabilities */
213*2810ac1bSKiyoung Kim 	op = *str++;
214*2810ac1bSKiyoung Kim 	if (op == '=' && (*str == '+' || *str == '-')) {
215*2810ac1bSKiyoung Kim 	    if (!listed)
216*2810ac1bSKiyoung Kim 		goto bad;
217*2810ac1bSKiyoung Kim 	    op = (*str++ == '+' ? 'P':'M'); /* skip '=' and take next op */
218*2810ac1bSKiyoung Kim 	} else if (op != '+' && op != '-' && op != '=')
219*2810ac1bSKiyoung Kim 	    goto bad;
220*2810ac1bSKiyoung Kim 
221*2810ac1bSKiyoung Kim 	/* cycle through list of actions */
222*2810ac1bSKiyoung Kim 	do {
223*2810ac1bSKiyoung Kim 	    _cap_debug("next char = '%c'", *str);
224*2810ac1bSKiyoung Kim 	    if (*str && !isspace(*str)) {
225*2810ac1bSKiyoung Kim 		switch (*str++) {    /* Effective, Inheritable, Permitted */
226*2810ac1bSKiyoung Kim 		case 'e':
227*2810ac1bSKiyoung Kim 		    flags |= LIBCAP_EFF;
228*2810ac1bSKiyoung Kim 		    break;
229*2810ac1bSKiyoung Kim 		case 'i':
230*2810ac1bSKiyoung Kim 		    flags |= LIBCAP_INH;
231*2810ac1bSKiyoung Kim 		    break;
232*2810ac1bSKiyoung Kim 		case 'p':
233*2810ac1bSKiyoung Kim 		    flags |= LIBCAP_PER;
234*2810ac1bSKiyoung Kim 		    break;
235*2810ac1bSKiyoung Kim 		default:
236*2810ac1bSKiyoung Kim 		    goto bad;
237*2810ac1bSKiyoung Kim 		}
238*2810ac1bSKiyoung Kim 	    } else if (op != '=') {
239*2810ac1bSKiyoung Kim 		_cap_debug("only '=' can be followed by space");
240*2810ac1bSKiyoung Kim 		goto bad;
241*2810ac1bSKiyoung Kim 	    }
242*2810ac1bSKiyoung Kim 
243*2810ac1bSKiyoung Kim 	    _cap_debug("how to read?");
244*2810ac1bSKiyoung Kim 	    switch (op) {               /* how do we interpret the caps? */
245*2810ac1bSKiyoung Kim 	    case '=':
246*2810ac1bSKiyoung Kim 	    case 'P':                                              /* =+ */
247*2810ac1bSKiyoung Kim 	    case 'M':                                              /* =- */
248*2810ac1bSKiyoung Kim 		clrbits(res, list, CAP_EFFECTIVE, cap_blks);
249*2810ac1bSKiyoung Kim 		clrbits(res, list, CAP_PERMITTED, cap_blks);
250*2810ac1bSKiyoung Kim 		clrbits(res, list, CAP_INHERITABLE, cap_blks);
251*2810ac1bSKiyoung Kim 		if (op == 'M')
252*2810ac1bSKiyoung Kim 		    goto minus;
253*2810ac1bSKiyoung Kim 		/* fall through */
254*2810ac1bSKiyoung Kim 	    case '+':
255*2810ac1bSKiyoung Kim 		if (flags & LIBCAP_EFF)
256*2810ac1bSKiyoung Kim 		    setbits(res, list, CAP_EFFECTIVE, cap_blks);
257*2810ac1bSKiyoung Kim 		if (flags & LIBCAP_PER)
258*2810ac1bSKiyoung Kim 		    setbits(res, list, CAP_PERMITTED, cap_blks);
259*2810ac1bSKiyoung Kim 		if (flags & LIBCAP_INH)
260*2810ac1bSKiyoung Kim 		    setbits(res, list, CAP_INHERITABLE, cap_blks);
261*2810ac1bSKiyoung Kim 		break;
262*2810ac1bSKiyoung Kim 	    case '-':
263*2810ac1bSKiyoung Kim 	    minus:
264*2810ac1bSKiyoung Kim 		if (flags & LIBCAP_EFF)
265*2810ac1bSKiyoung Kim 		    clrbits(res, list, CAP_EFFECTIVE, cap_blks);
266*2810ac1bSKiyoung Kim 		if (flags & LIBCAP_PER)
267*2810ac1bSKiyoung Kim 		    clrbits(res, list, CAP_PERMITTED, cap_blks);
268*2810ac1bSKiyoung Kim 		if (flags & LIBCAP_INH)
269*2810ac1bSKiyoung Kim 		    clrbits(res, list, CAP_INHERITABLE, cap_blks);
270*2810ac1bSKiyoung Kim 		break;
271*2810ac1bSKiyoung Kim 	    }
272*2810ac1bSKiyoung Kim 
273*2810ac1bSKiyoung Kim 	    /* new directive? */
274*2810ac1bSKiyoung Kim 	    if (*str == '+' || *str == '-') {
275*2810ac1bSKiyoung Kim 		if (!listed) {
276*2810ac1bSKiyoung Kim 		    _cap_debug("for + & - must list capabilities");
277*2810ac1bSKiyoung Kim 		    goto bad;
278*2810ac1bSKiyoung Kim 		}
279*2810ac1bSKiyoung Kim 		flags = 0;                       /* reset the flags */
280*2810ac1bSKiyoung Kim 		op = *str++;
281*2810ac1bSKiyoung Kim 		if (!isalpha(*str))
282*2810ac1bSKiyoung Kim 		    goto bad;
283*2810ac1bSKiyoung Kim 	    }
284*2810ac1bSKiyoung Kim 	} while (*str && !isspace(*str));
285*2810ac1bSKiyoung Kim 	_cap_debug("next clause");
286*2810ac1bSKiyoung Kim     }
287*2810ac1bSKiyoung Kim 
288*2810ac1bSKiyoung Kim bad:
289*2810ac1bSKiyoung Kim     cap_free(res);
290*2810ac1bSKiyoung Kim     res = NULL;
291*2810ac1bSKiyoung Kim     errno = EINVAL;
292*2810ac1bSKiyoung Kim     return res;
293*2810ac1bSKiyoung Kim }
294*2810ac1bSKiyoung Kim 
295*2810ac1bSKiyoung Kim /*
296*2810ac1bSKiyoung Kim  * lookup a capability name and return its numerical value
297*2810ac1bSKiyoung Kim  */
cap_from_name(const char * name,cap_value_t * value_p)298*2810ac1bSKiyoung Kim int cap_from_name(const char *name, cap_value_t *value_p)
299*2810ac1bSKiyoung Kim {
300*2810ac1bSKiyoung Kim     int n;
301*2810ac1bSKiyoung Kim 
302*2810ac1bSKiyoung Kim     if (((n = lookupname(&name)) >= 0) && (value_p != NULL)) {
303*2810ac1bSKiyoung Kim 	*value_p = (unsigned) n;
304*2810ac1bSKiyoung Kim     }
305*2810ac1bSKiyoung Kim     return -(n < 0);
306*2810ac1bSKiyoung Kim }
307*2810ac1bSKiyoung Kim 
308*2810ac1bSKiyoung Kim /*
309*2810ac1bSKiyoung Kim  * Convert a single capability index number into a string representation
310*2810ac1bSKiyoung Kim  */
cap_to_name(cap_value_t cap)311*2810ac1bSKiyoung Kim char *cap_to_name(cap_value_t cap)
312*2810ac1bSKiyoung Kim {
313*2810ac1bSKiyoung Kim     char *tmp, *result;
314*2810ac1bSKiyoung Kim 
315*2810ac1bSKiyoung Kim     if ((cap >= 0) && (cap < __CAP_BITS)) {
316*2810ac1bSKiyoung Kim 	return _libcap_strdup(_cap_names[cap]);
317*2810ac1bSKiyoung Kim     }
318*2810ac1bSKiyoung Kim     if (asprintf(&tmp, "%u", cap) <= 0) {
319*2810ac1bSKiyoung Kim 	_cap_debug("asprintf filed");
320*2810ac1bSKiyoung Kim 	return NULL;
321*2810ac1bSKiyoung Kim     }
322*2810ac1bSKiyoung Kim 
323*2810ac1bSKiyoung Kim     result = _libcap_strdup(tmp);
324*2810ac1bSKiyoung Kim     free(tmp);
325*2810ac1bSKiyoung Kim     return result;
326*2810ac1bSKiyoung Kim }
327*2810ac1bSKiyoung Kim 
328*2810ac1bSKiyoung Kim /*
329*2810ac1bSKiyoung Kim  * Convert an internal representation to a textual one. The textual
330*2810ac1bSKiyoung Kim  * representation is stored in static memory. It will be overwritten
331*2810ac1bSKiyoung Kim  * on the next occasion that this function is called.
332*2810ac1bSKiyoung Kim  */
333*2810ac1bSKiyoung Kim 
getstateflags(cap_t caps,int capno)334*2810ac1bSKiyoung Kim static int getstateflags(cap_t caps, int capno)
335*2810ac1bSKiyoung Kim {
336*2810ac1bSKiyoung Kim     int f = 0;
337*2810ac1bSKiyoung Kim 
338*2810ac1bSKiyoung Kim     if (isset_cap(caps, capno, CAP_EFFECTIVE)) {
339*2810ac1bSKiyoung Kim 	f |= LIBCAP_EFF;
340*2810ac1bSKiyoung Kim     }
341*2810ac1bSKiyoung Kim     if (isset_cap(caps, capno, CAP_PERMITTED)) {
342*2810ac1bSKiyoung Kim 	f |= LIBCAP_PER;
343*2810ac1bSKiyoung Kim     }
344*2810ac1bSKiyoung Kim     if (isset_cap(caps, capno, CAP_INHERITABLE)) {
345*2810ac1bSKiyoung Kim 	f |= LIBCAP_INH;
346*2810ac1bSKiyoung Kim     }
347*2810ac1bSKiyoung Kim 
348*2810ac1bSKiyoung Kim     return f;
349*2810ac1bSKiyoung Kim }
350*2810ac1bSKiyoung Kim 
351*2810ac1bSKiyoung Kim /*
352*2810ac1bSKiyoung Kim  * This code assumes that the longest named capability is longer than
353*2810ac1bSKiyoung Kim  * the decimal text representation of __CAP_MAXBITS. This is very true
354*2810ac1bSKiyoung Kim  * at the time of writing and likely to remain so. However, we have
355*2810ac1bSKiyoung Kim  * a test in cap_text to validate it at build time.
356*2810ac1bSKiyoung Kim  */
357*2810ac1bSKiyoung Kim #define CAP_TEXT_BUFFER_ZONE 100
358*2810ac1bSKiyoung Kim 
cap_to_text(cap_t caps,ssize_t * length_p)359*2810ac1bSKiyoung Kim char *cap_to_text(cap_t caps, ssize_t *length_p)
360*2810ac1bSKiyoung Kim {
361*2810ac1bSKiyoung Kim     char buf[CAP_TEXT_SIZE+CAP_TEXT_BUFFER_ZONE];
362*2810ac1bSKiyoung Kim     char *p, *base;
363*2810ac1bSKiyoung Kim     int histo[8];
364*2810ac1bSKiyoung Kim     int m, t;
365*2810ac1bSKiyoung Kim     unsigned n;
366*2810ac1bSKiyoung Kim 
367*2810ac1bSKiyoung Kim     /* Check arguments */
368*2810ac1bSKiyoung Kim     if (!good_cap_t(caps)) {
369*2810ac1bSKiyoung Kim 	errno = EINVAL;
370*2810ac1bSKiyoung Kim 	return NULL;
371*2810ac1bSKiyoung Kim     }
372*2810ac1bSKiyoung Kim 
373*2810ac1bSKiyoung Kim     _cap_debugcap("e = ", *caps, CAP_EFFECTIVE);
374*2810ac1bSKiyoung Kim     _cap_debugcap("i = ", *caps, CAP_INHERITABLE);
375*2810ac1bSKiyoung Kim     _cap_debugcap("p = ", *caps, CAP_PERMITTED);
376*2810ac1bSKiyoung Kim 
377*2810ac1bSKiyoung Kim     memset(histo, 0, sizeof(histo));
378*2810ac1bSKiyoung Kim 
379*2810ac1bSKiyoung Kim     /* default prevailing state to the named bits */
380*2810ac1bSKiyoung Kim     cap_value_t cmb = cap_max_bits();
381*2810ac1bSKiyoung Kim     for (n = 0; n < cmb; n++)
382*2810ac1bSKiyoung Kim 	histo[getstateflags(caps, n)]++;
383*2810ac1bSKiyoung Kim 
384*2810ac1bSKiyoung Kim     /* find which combination of capability sets shares the most bits
385*2810ac1bSKiyoung Kim        we bias to preferring non-set (m=0) with the >= 0 test. Failing
386*2810ac1bSKiyoung Kim        to do this causes strange things to happen with older systems
387*2810ac1bSKiyoung Kim        that don't know about bits 32+. */
388*2810ac1bSKiyoung Kim     for (m=t=7; t--; )
389*2810ac1bSKiyoung Kim 	if (histo[t] >= histo[m])
390*2810ac1bSKiyoung Kim 	    m = t;
391*2810ac1bSKiyoung Kim 
392*2810ac1bSKiyoung Kim     /* blank is not a valid capability set */
393*2810ac1bSKiyoung Kim     base = buf;
394*2810ac1bSKiyoung Kim     p = sprintf(buf, "=%s%s%s",
395*2810ac1bSKiyoung Kim 		(m & LIBCAP_EFF) ? "e" : "",
396*2810ac1bSKiyoung Kim 		(m & LIBCAP_INH) ? "i" : "",
397*2810ac1bSKiyoung Kim 		(m & LIBCAP_PER) ? "p" : "" ) + buf;
398*2810ac1bSKiyoung Kim 
399*2810ac1bSKiyoung Kim     for (t = 8; t--; ) {
400*2810ac1bSKiyoung Kim 	if (t == m || !histo[t]) {
401*2810ac1bSKiyoung Kim 	    continue;
402*2810ac1bSKiyoung Kim 	}
403*2810ac1bSKiyoung Kim 	*p++ = ' ';
404*2810ac1bSKiyoung Kim 	for (n = 0; n < cmb; n++) {
405*2810ac1bSKiyoung Kim 	    if (getstateflags(caps, n) == t) {
406*2810ac1bSKiyoung Kim 	        char *this_cap_name = cap_to_name(n);
407*2810ac1bSKiyoung Kim 		if (this_cap_name == NULL) {
408*2810ac1bSKiyoung Kim 		    return NULL;
409*2810ac1bSKiyoung Kim 		}
410*2810ac1bSKiyoung Kim 	        if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
411*2810ac1bSKiyoung Kim 		    cap_free(this_cap_name);
412*2810ac1bSKiyoung Kim 		    errno = ERANGE;
413*2810ac1bSKiyoung Kim 		    return NULL;
414*2810ac1bSKiyoung Kim 	        }
415*2810ac1bSKiyoung Kim 	        p += sprintf(p, "%s,", this_cap_name);
416*2810ac1bSKiyoung Kim 	        cap_free(this_cap_name);
417*2810ac1bSKiyoung Kim 	    }
418*2810ac1bSKiyoung Kim 	}
419*2810ac1bSKiyoung Kim 	p--;
420*2810ac1bSKiyoung Kim 	n = t & ~m;
421*2810ac1bSKiyoung Kim 	if (n) {
422*2810ac1bSKiyoung Kim 	    char op = '+';
423*2810ac1bSKiyoung Kim 	    if (base[0] == '=' && base[1] == ' ') {
424*2810ac1bSKiyoung Kim 		/*
425*2810ac1bSKiyoung Kim 		 * Special case all lowered default "= foo,...+eip
426*2810ac1bSKiyoung Kim 		 * ..." as "foo,...=eip ...". (Equivalent but shorter.)
427*2810ac1bSKiyoung Kim 		 */
428*2810ac1bSKiyoung Kim 		base += 2;
429*2810ac1bSKiyoung Kim 		op = '=';
430*2810ac1bSKiyoung Kim 	    }
431*2810ac1bSKiyoung Kim 	    p += sprintf(p, "%c%s%s%s", op,
432*2810ac1bSKiyoung Kim 			 (n & LIBCAP_EFF) ? "e" : "",
433*2810ac1bSKiyoung Kim 			 (n & LIBCAP_INH) ? "i" : "",
434*2810ac1bSKiyoung Kim 			 (n & LIBCAP_PER) ? "p" : "");
435*2810ac1bSKiyoung Kim 	}
436*2810ac1bSKiyoung Kim 	n = ~t & m;
437*2810ac1bSKiyoung Kim 	if (n) {
438*2810ac1bSKiyoung Kim 	    p += sprintf(p, "-%s%s%s",
439*2810ac1bSKiyoung Kim 			 (n & LIBCAP_EFF) ? "e" : "",
440*2810ac1bSKiyoung Kim 			 (n & LIBCAP_INH) ? "i" : "",
441*2810ac1bSKiyoung Kim 			 (n & LIBCAP_PER) ? "p" : "");
442*2810ac1bSKiyoung Kim 	}
443*2810ac1bSKiyoung Kim 	if (p - buf > CAP_TEXT_SIZE) {
444*2810ac1bSKiyoung Kim 	    errno = ERANGE;
445*2810ac1bSKiyoung Kim 	    return NULL;
446*2810ac1bSKiyoung Kim 	}
447*2810ac1bSKiyoung Kim     }
448*2810ac1bSKiyoung Kim 
449*2810ac1bSKiyoung Kim     /* capture remaining unnamed bits - which must all be +. */
450*2810ac1bSKiyoung Kim     memset(histo, 0, sizeof(histo));
451*2810ac1bSKiyoung Kim     for (n = cmb; n < __CAP_MAXBITS; n++)
452*2810ac1bSKiyoung Kim 	histo[getstateflags(caps, n)]++;
453*2810ac1bSKiyoung Kim 
454*2810ac1bSKiyoung Kim     for (t = 8; t-- > 1; ) {
455*2810ac1bSKiyoung Kim 	if (!histo[t]) {
456*2810ac1bSKiyoung Kim 	    continue;
457*2810ac1bSKiyoung Kim 	}
458*2810ac1bSKiyoung Kim 	*p++ = ' ';
459*2810ac1bSKiyoung Kim 	for (n = cmb; n < __CAP_MAXBITS; n++) {
460*2810ac1bSKiyoung Kim 	    if (getstateflags(caps, n) == t) {
461*2810ac1bSKiyoung Kim 		char *this_cap_name = cap_to_name(n);
462*2810ac1bSKiyoung Kim 		if (this_cap_name == NULL) {
463*2810ac1bSKiyoung Kim 		    return NULL;
464*2810ac1bSKiyoung Kim 		}
465*2810ac1bSKiyoung Kim 	        if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
466*2810ac1bSKiyoung Kim 		    cap_free(this_cap_name);
467*2810ac1bSKiyoung Kim 		    errno = ERANGE;
468*2810ac1bSKiyoung Kim 		    return NULL;
469*2810ac1bSKiyoung Kim 	        }
470*2810ac1bSKiyoung Kim 		p += sprintf(p, "%s,", this_cap_name);
471*2810ac1bSKiyoung Kim 		cap_free(this_cap_name);
472*2810ac1bSKiyoung Kim 	    }
473*2810ac1bSKiyoung Kim 	}
474*2810ac1bSKiyoung Kim 	p--;
475*2810ac1bSKiyoung Kim 	p += sprintf(p, "+%s%s%s",
476*2810ac1bSKiyoung Kim 		     (t & LIBCAP_EFF) ? "e" : "",
477*2810ac1bSKiyoung Kim 		     (t & LIBCAP_INH) ? "i" : "",
478*2810ac1bSKiyoung Kim 		     (t & LIBCAP_PER) ? "p" : "");
479*2810ac1bSKiyoung Kim 	if (p - buf > CAP_TEXT_SIZE) {
480*2810ac1bSKiyoung Kim 	    errno = ERANGE;
481*2810ac1bSKiyoung Kim 	    return NULL;
482*2810ac1bSKiyoung Kim 	}
483*2810ac1bSKiyoung Kim     }
484*2810ac1bSKiyoung Kim 
485*2810ac1bSKiyoung Kim     _cap_debug("%s", base);
486*2810ac1bSKiyoung Kim     if (length_p) {
487*2810ac1bSKiyoung Kim 	*length_p = p - base;
488*2810ac1bSKiyoung Kim     }
489*2810ac1bSKiyoung Kim 
490*2810ac1bSKiyoung Kim     return (_libcap_strdup(base));
491*2810ac1bSKiyoung Kim }
492*2810ac1bSKiyoung Kim 
493*2810ac1bSKiyoung Kim /*
494*2810ac1bSKiyoung Kim  * cap_mode_name returns a text token naming the specified mode.
495*2810ac1bSKiyoung Kim  */
cap_mode_name(cap_mode_t flavor)496*2810ac1bSKiyoung Kim const char *cap_mode_name(cap_mode_t flavor) {
497*2810ac1bSKiyoung Kim     switch (flavor) {
498*2810ac1bSKiyoung Kim     case CAP_MODE_NOPRIV:
499*2810ac1bSKiyoung Kim 	return "NOPRIV";
500*2810ac1bSKiyoung Kim     case CAP_MODE_PURE1E_INIT:
501*2810ac1bSKiyoung Kim 	return "PURE1E_INIT";
502*2810ac1bSKiyoung Kim     case CAP_MODE_PURE1E:
503*2810ac1bSKiyoung Kim 	return "PURE1E";
504*2810ac1bSKiyoung Kim     case CAP_MODE_UNCERTAIN:
505*2810ac1bSKiyoung Kim 	return "UNCERTAIN";
506*2810ac1bSKiyoung Kim     case CAP_MODE_HYBRID:
507*2810ac1bSKiyoung Kim 	return "HYBRID";
508*2810ac1bSKiyoung Kim     default:
509*2810ac1bSKiyoung Kim 	return "UNKNOWN";
510*2810ac1bSKiyoung Kim     }
511*2810ac1bSKiyoung Kim }
512*2810ac1bSKiyoung Kim 
513*2810ac1bSKiyoung Kim /*
514*2810ac1bSKiyoung Kim  * cap_iab_to_text serializes an iab into a canonical text
515*2810ac1bSKiyoung Kim  * representation.
516*2810ac1bSKiyoung Kim  */
cap_iab_to_text(cap_iab_t iab)517*2810ac1bSKiyoung Kim char *cap_iab_to_text(cap_iab_t iab)
518*2810ac1bSKiyoung Kim {
519*2810ac1bSKiyoung Kim     char buf[CAP_TEXT_SIZE+CAP_TEXT_BUFFER_ZONE];
520*2810ac1bSKiyoung Kim     char *p = buf;
521*2810ac1bSKiyoung Kim     cap_value_t c, cmb = cap_max_bits();
522*2810ac1bSKiyoung Kim     int first = 1;
523*2810ac1bSKiyoung Kim 
524*2810ac1bSKiyoung Kim     if (good_cap_iab_t(iab)) {
525*2810ac1bSKiyoung Kim 	_cap_mu_lock(&iab->mutex);
526*2810ac1bSKiyoung Kim 	for (c = 0; c < cmb; c++) {
527*2810ac1bSKiyoung Kim 	    int keep = 0;
528*2810ac1bSKiyoung Kim 	    int o = c >> 5;
529*2810ac1bSKiyoung Kim 	    __u32 bit = 1U << (c & 31);
530*2810ac1bSKiyoung Kim 	    __u32 ib = iab->i[o] & bit;
531*2810ac1bSKiyoung Kim 	    __u32 ab = iab->a[o] & bit;
532*2810ac1bSKiyoung Kim 	    __u32 nbb = iab->nb[o] & bit;
533*2810ac1bSKiyoung Kim 	    if (!(nbb | ab | ib)) {
534*2810ac1bSKiyoung Kim 		continue;
535*2810ac1bSKiyoung Kim 	    }
536*2810ac1bSKiyoung Kim 	    if (!first) {
537*2810ac1bSKiyoung Kim 		*p++ = ',';
538*2810ac1bSKiyoung Kim 	    }
539*2810ac1bSKiyoung Kim 	    if (nbb) {
540*2810ac1bSKiyoung Kim 		*p++ = '!';
541*2810ac1bSKiyoung Kim 		keep = 1;
542*2810ac1bSKiyoung Kim 	    }
543*2810ac1bSKiyoung Kim 	    if (ab) {
544*2810ac1bSKiyoung Kim 		*p++ = '^';
545*2810ac1bSKiyoung Kim 		keep = 1;
546*2810ac1bSKiyoung Kim 	    } else if (nbb && ib) {
547*2810ac1bSKiyoung Kim 		*p++ = '%';
548*2810ac1bSKiyoung Kim 	    }
549*2810ac1bSKiyoung Kim 	    if (keep || ib) {
550*2810ac1bSKiyoung Kim 		if (c < __CAP_BITS) {
551*2810ac1bSKiyoung Kim 		    strcpy(p, _cap_names[c]);
552*2810ac1bSKiyoung Kim 		} else {
553*2810ac1bSKiyoung Kim 		    sprintf(p, "%u", c);
554*2810ac1bSKiyoung Kim 		}
555*2810ac1bSKiyoung Kim 		p += strlen(p);
556*2810ac1bSKiyoung Kim 		first = 0;
557*2810ac1bSKiyoung Kim 	    }
558*2810ac1bSKiyoung Kim 	}
559*2810ac1bSKiyoung Kim 	_cap_mu_unlock(&iab->mutex);
560*2810ac1bSKiyoung Kim     }
561*2810ac1bSKiyoung Kim     *p = '\0';
562*2810ac1bSKiyoung Kim     return _libcap_strdup(buf);
563*2810ac1bSKiyoung Kim }
564*2810ac1bSKiyoung Kim 
cap_iab_from_text(const char * text)565*2810ac1bSKiyoung Kim cap_iab_t cap_iab_from_text(const char *text)
566*2810ac1bSKiyoung Kim {
567*2810ac1bSKiyoung Kim     cap_iab_t iab = cap_iab_init();
568*2810ac1bSKiyoung Kim     if (iab == NULL) {
569*2810ac1bSKiyoung Kim 	return iab;
570*2810ac1bSKiyoung Kim     }
571*2810ac1bSKiyoung Kim     if (text != NULL) {
572*2810ac1bSKiyoung Kim 	unsigned flags;
573*2810ac1bSKiyoung Kim 	for (flags = 0; *text; text++) {
574*2810ac1bSKiyoung Kim 	    /* consume prefixes */
575*2810ac1bSKiyoung Kim 	    switch (*text) {
576*2810ac1bSKiyoung Kim 	    case '!':
577*2810ac1bSKiyoung Kim 		flags |= LIBCAP_IAB_NB_FLAG;
578*2810ac1bSKiyoung Kim 		continue;
579*2810ac1bSKiyoung Kim 	    case '^':
580*2810ac1bSKiyoung Kim 		flags |= LIBCAP_IAB_IA_FLAG;
581*2810ac1bSKiyoung Kim 		continue;
582*2810ac1bSKiyoung Kim 	    case '%':
583*2810ac1bSKiyoung Kim 		flags |= LIBCAP_IAB_I_FLAG;
584*2810ac1bSKiyoung Kim 		continue;
585*2810ac1bSKiyoung Kim 	    default:
586*2810ac1bSKiyoung Kim 		break;
587*2810ac1bSKiyoung Kim 	    }
588*2810ac1bSKiyoung Kim 	    if (!flags) {
589*2810ac1bSKiyoung Kim 		flags = LIBCAP_IAB_I_FLAG;
590*2810ac1bSKiyoung Kim 	    }
591*2810ac1bSKiyoung Kim 
592*2810ac1bSKiyoung Kim 	    /* consume cap name */
593*2810ac1bSKiyoung Kim 	    cap_value_t c = lookupname(&text);
594*2810ac1bSKiyoung Kim 	    if (c == -1) {
595*2810ac1bSKiyoung Kim 		goto cleanup;
596*2810ac1bSKiyoung Kim 	    }
597*2810ac1bSKiyoung Kim 	    unsigned o = c >> 5;
598*2810ac1bSKiyoung Kim 	    __u32 mask = 1U << (c & 31);
599*2810ac1bSKiyoung Kim 	    if (flags & LIBCAP_IAB_I_FLAG) {
600*2810ac1bSKiyoung Kim 		iab->i[o] |= mask;
601*2810ac1bSKiyoung Kim 	    }
602*2810ac1bSKiyoung Kim 	    if (flags & LIBCAP_IAB_A_FLAG) {
603*2810ac1bSKiyoung Kim 		iab->a[o] |= mask;
604*2810ac1bSKiyoung Kim 	    }
605*2810ac1bSKiyoung Kim 	    if (flags & LIBCAP_IAB_NB_FLAG) {
606*2810ac1bSKiyoung Kim 		iab->nb[o] |= mask;
607*2810ac1bSKiyoung Kim 	    }
608*2810ac1bSKiyoung Kim 
609*2810ac1bSKiyoung Kim 	    /* rest should be end or comma */
610*2810ac1bSKiyoung Kim 	    if (*text == '\0') {
611*2810ac1bSKiyoung Kim 		break;
612*2810ac1bSKiyoung Kim 	    }
613*2810ac1bSKiyoung Kim 	    if (*text != ',') {
614*2810ac1bSKiyoung Kim 		goto cleanup;
615*2810ac1bSKiyoung Kim 	    }
616*2810ac1bSKiyoung Kim 	    flags = 0;
617*2810ac1bSKiyoung Kim 	}
618*2810ac1bSKiyoung Kim     }
619*2810ac1bSKiyoung Kim     return iab;
620*2810ac1bSKiyoung Kim 
621*2810ac1bSKiyoung Kim cleanup:
622*2810ac1bSKiyoung Kim     cap_free(iab);
623*2810ac1bSKiyoung Kim     errno = EINVAL;
624*2810ac1bSKiyoung Kim     return NULL;
625*2810ac1bSKiyoung Kim }
626*2810ac1bSKiyoung Kim 
_parse_hex32(const char * c)627*2810ac1bSKiyoung Kim static __u32 _parse_hex32(const char *c)
628*2810ac1bSKiyoung Kim {
629*2810ac1bSKiyoung Kim     int i;
630*2810ac1bSKiyoung Kim     __u32 v = 0;
631*2810ac1bSKiyoung Kim     for (i=0; i < 8; i++, c++) {
632*2810ac1bSKiyoung Kim 	v <<= 4;
633*2810ac1bSKiyoung Kim 	if (*c == 0 || *c < '0') {
634*2810ac1bSKiyoung Kim 	    return 0;
635*2810ac1bSKiyoung Kim 	} else if (*c <= '9') {
636*2810ac1bSKiyoung Kim 	    v += *c - '0';
637*2810ac1bSKiyoung Kim 	} else if (*c > 'f') {
638*2810ac1bSKiyoung Kim 	    return 0;
639*2810ac1bSKiyoung Kim 	} else if (*c >= 'a') {
640*2810ac1bSKiyoung Kim 	    v += *c + 10 - 'a';
641*2810ac1bSKiyoung Kim 	} else if (*c < 'A') {
642*2810ac1bSKiyoung Kim 	    return 0;
643*2810ac1bSKiyoung Kim 	} else if (*c <= 'F') {
644*2810ac1bSKiyoung Kim 	    v += *c + 10 - 'A';
645*2810ac1bSKiyoung Kim 	} else {
646*2810ac1bSKiyoung Kim 	    return 0;
647*2810ac1bSKiyoung Kim 	}
648*2810ac1bSKiyoung Kim     }
649*2810ac1bSKiyoung Kim     return v;
650*2810ac1bSKiyoung Kim }
651*2810ac1bSKiyoung Kim 
652*2810ac1bSKiyoung Kim /*
653*2810ac1bSKiyoung Kim  * _parse_vec_string converts the hex dumps in /proc/<pid>/current into
654*2810ac1bSKiyoung Kim  * an array of u32s - masked as per the forceall() mask.
655*2810ac1bSKiyoung Kim  */
_parse_vec_string(__u32 * vals,const char * c,int invert)656*2810ac1bSKiyoung Kim static __u32 _parse_vec_string(__u32 *vals, const char *c, int invert)
657*2810ac1bSKiyoung Kim {
658*2810ac1bSKiyoung Kim     int i;
659*2810ac1bSKiyoung Kim     int words = strlen(c)/8;
660*2810ac1bSKiyoung Kim     if (words > _LIBCAP_CAPABILITY_U32S) {
661*2810ac1bSKiyoung Kim 	return 0;
662*2810ac1bSKiyoung Kim     }
663*2810ac1bSKiyoung Kim     forceall(vals, ~0, words);
664*2810ac1bSKiyoung Kim     for (i = 0; i < words; i++) {
665*2810ac1bSKiyoung Kim 	__u32 val = _parse_hex32(c+8*(words-1-i));
666*2810ac1bSKiyoung Kim 	if (invert) {
667*2810ac1bSKiyoung Kim 	    val = ~val;
668*2810ac1bSKiyoung Kim 	}
669*2810ac1bSKiyoung Kim 	vals[i] &= val;
670*2810ac1bSKiyoung Kim     }
671*2810ac1bSKiyoung Kim     return ~0;
672*2810ac1bSKiyoung Kim }
673*2810ac1bSKiyoung Kim 
674*2810ac1bSKiyoung Kim /*
675*2810ac1bSKiyoung Kim  * libcap believes this is the root of the mounted "/proc"
676*2810ac1bSKiyoung Kim  * filesystem. (NULL == "/proc".)
677*2810ac1bSKiyoung Kim  */
678*2810ac1bSKiyoung Kim static char *_cap_proc_dir;
679*2810ac1bSKiyoung Kim 
680*2810ac1bSKiyoung Kim /*
681*2810ac1bSKiyoung Kim  * If the constructor is called (see cap_alloc.c) then we'll need the
682*2810ac1bSKiyoung Kim  * corresponding destructor.
683*2810ac1bSKiyoung Kim  */
_cleanup_libcap(void)684*2810ac1bSKiyoung Kim __attribute__((destructor (300))) static void _cleanup_libcap(void)
685*2810ac1bSKiyoung Kim {
686*2810ac1bSKiyoung Kim     if (_cap_proc_dir == NULL) {
687*2810ac1bSKiyoung Kim 	return;
688*2810ac1bSKiyoung Kim     }
689*2810ac1bSKiyoung Kim     cap_free(_cap_proc_dir);
690*2810ac1bSKiyoung Kim     _cap_proc_dir = NULL;
691*2810ac1bSKiyoung Kim }
692*2810ac1bSKiyoung Kim 
693*2810ac1bSKiyoung Kim /*
694*2810ac1bSKiyoung Kim  * cap_proc_root reads and (optionally: when root != NULL) changes
695*2810ac1bSKiyoung Kim  * libcap's notion of where the "/proc" filesystem is mounted. It
696*2810ac1bSKiyoung Kim  * defaults to the value "/proc". Note, this is a global value and not
697*2810ac1bSKiyoung Kim  * considered thread safe to write - so the client should take
698*2810ac1bSKiyoung Kim  * suitable care when changing it. Further, libcap will allocate
699*2810ac1bSKiyoung Kim  * memory for storing the replacement root, and it is this memory that
700*2810ac1bSKiyoung Kim  * is returned. So, when changing the value, the caller should
701*2810ac1bSKiyoung Kim  * cap_free(the-return-value) when done with it.
702*2810ac1bSKiyoung Kim  *
703*2810ac1bSKiyoung Kim  * A return value of NULL implies the default is in effect "/proc".
704*2810ac1bSKiyoung Kim  */
cap_proc_root(const char * root)705*2810ac1bSKiyoung Kim char *cap_proc_root(const char *root)
706*2810ac1bSKiyoung Kim {
707*2810ac1bSKiyoung Kim     char *old = _cap_proc_dir;
708*2810ac1bSKiyoung Kim     if (root != NULL) {
709*2810ac1bSKiyoung Kim 	_cap_proc_dir = _libcap_strdup(root);
710*2810ac1bSKiyoung Kim     }
711*2810ac1bSKiyoung Kim     return old;
712*2810ac1bSKiyoung Kim }
713*2810ac1bSKiyoung Kim 
714*2810ac1bSKiyoung Kim #define PROC_LINE_MAX (8 + 8*_LIBCAP_CAPABILITY_U32S + 100)
715*2810ac1bSKiyoung Kim /*
716*2810ac1bSKiyoung Kim  * cap_iab_get_pid fills an IAB tuple from the content of
717*2810ac1bSKiyoung Kim  * /proc/<pid>/status. Linux doesn't support syscall access to the
718*2810ac1bSKiyoung Kim  * needed information, so we parse it out of that file.
719*2810ac1bSKiyoung Kim  */
cap_iab_get_pid(pid_t pid)720*2810ac1bSKiyoung Kim cap_iab_t cap_iab_get_pid(pid_t pid)
721*2810ac1bSKiyoung Kim {
722*2810ac1bSKiyoung Kim     cap_iab_t iab;
723*2810ac1bSKiyoung Kim     char *path;
724*2810ac1bSKiyoung Kim     FILE *file;
725*2810ac1bSKiyoung Kim     char line[PROC_LINE_MAX];
726*2810ac1bSKiyoung Kim     const char *proc_root = _cap_proc_dir;
727*2810ac1bSKiyoung Kim 
728*2810ac1bSKiyoung Kim     if (proc_root == NULL) {
729*2810ac1bSKiyoung Kim 	proc_root = "/proc";
730*2810ac1bSKiyoung Kim     }
731*2810ac1bSKiyoung Kim     if (asprintf(&path, "%s/%d/status", proc_root, pid) <= 0) {
732*2810ac1bSKiyoung Kim 	return NULL;
733*2810ac1bSKiyoung Kim     }
734*2810ac1bSKiyoung Kim     file = fopen(path, "r");
735*2810ac1bSKiyoung Kim     free(path);
736*2810ac1bSKiyoung Kim     if (file == NULL) {
737*2810ac1bSKiyoung Kim 	return NULL;
738*2810ac1bSKiyoung Kim     }
739*2810ac1bSKiyoung Kim 
740*2810ac1bSKiyoung Kim     iab = cap_iab_init();
741*2810ac1bSKiyoung Kim     uint ok = 0;
742*2810ac1bSKiyoung Kim     if (iab != NULL) {
743*2810ac1bSKiyoung Kim 	while (fgets(line, PROC_LINE_MAX-1, file) != NULL) {
744*2810ac1bSKiyoung Kim 	    if (strncmp("Cap", line, 3) != 0) {
745*2810ac1bSKiyoung Kim 		continue;
746*2810ac1bSKiyoung Kim 	    }
747*2810ac1bSKiyoung Kim 	    if (strncmp("Inh:\t", line+3, 5) == 0) {
748*2810ac1bSKiyoung Kim 		ok = (_parse_vec_string(iab->i, line+8, 0) &
749*2810ac1bSKiyoung Kim 		    LIBCAP_IAB_I_FLAG) | ok;
750*2810ac1bSKiyoung Kim 		continue;
751*2810ac1bSKiyoung Kim 	    }
752*2810ac1bSKiyoung Kim 	    if (strncmp("Bnd:\t", line+3, 5) == 0) {
753*2810ac1bSKiyoung Kim 		ok = (_parse_vec_string(iab->nb, line+8, 1) &
754*2810ac1bSKiyoung Kim 		      LIBCAP_IAB_NB_FLAG) | ok;
755*2810ac1bSKiyoung Kim 		continue;
756*2810ac1bSKiyoung Kim 	    }
757*2810ac1bSKiyoung Kim 	    if (strncmp("Amb:\t", line+3, 5) == 0) {
758*2810ac1bSKiyoung Kim 		ok = (_parse_vec_string(iab->a, line+8, 0) &
759*2810ac1bSKiyoung Kim 		      LIBCAP_IAB_A_FLAG) | ok;
760*2810ac1bSKiyoung Kim 		continue;
761*2810ac1bSKiyoung Kim 	    }
762*2810ac1bSKiyoung Kim 	}
763*2810ac1bSKiyoung Kim     }
764*2810ac1bSKiyoung Kim     if (ok != (LIBCAP_IAB_IA_FLAG | LIBCAP_IAB_NB_FLAG)) {
765*2810ac1bSKiyoung Kim 	cap_free(iab);
766*2810ac1bSKiyoung Kim 	iab = NULL;
767*2810ac1bSKiyoung Kim     }
768*2810ac1bSKiyoung Kim     fclose(file);
769*2810ac1bSKiyoung Kim     return iab;
770*2810ac1bSKiyoung Kim }
771