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