• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1997-8,2007-8 Andrew G Morgan <morgan@kernel.org>
3  * Copyright (c) 1997 Andrew Main <zefram@dcs.warwick.ac.uk>
4  *
5  * This file deals with exchanging internal and textual
6  * representations of capability sets.
7  */
8 
9 #define _GNU_SOURCE
10 #include <stdio.h>
11 
12 #define LIBCAP_PLEASE_INCLUDE_ARRAY
13 #include "libcap.h"
14 
15 #include <ctype.h>
16 #include <limits.h>
17 
18 /* Maximum output text length (16 per cap) */
19 #define CAP_TEXT_SIZE    (16*__CAP_MAXBITS)
20 
21 /*
22  * Parse a textual representation of capabilities, returning an internal
23  * representation.
24  */
25 
26 #define raise_cap_mask(flat, c)  (flat)[CAP_TO_INDEX(c)] |= CAP_TO_MASK(c)
27 
setbits(cap_t a,const __u32 * b,cap_flag_t set,unsigned blks)28 static void setbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks)
29 {
30     int n;
31     for (n = blks; n--; ) {
32 	a->u[n].flat[set] |= b[n];
33     }
34 }
35 
clrbits(cap_t a,const __u32 * b,cap_flag_t set,unsigned blks)36 static void clrbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks)
37 {
38     int n;
39     for (n = blks; n--; )
40 	a->u[n].flat[set] &= ~b[n];
41 }
42 
namcmp(char const * str,char const * nam)43 static char const *namcmp(char const *str, char const *nam)
44 {
45     while (*nam && tolower((unsigned char)*str) == *nam) {
46 	str++;
47 	nam++;
48     }
49     if (*nam || isalnum((unsigned char)*str) || *str == '_')
50 	return NULL;
51     return str;
52 }
53 
forceall(__u32 * flat,__u32 value,unsigned blks)54 static void forceall(__u32 *flat, __u32 value, unsigned blks)
55 {
56     unsigned n;
57 
58     for (n = blks; n--; flat[n] = value);
59 
60     return;
61 }
62 
lookupname(char const ** strp)63 static int lookupname(char const **strp)
64 {
65     union {
66 	char const *constp;
67 	char *p;
68     } str;
69 
70     str.constp = *strp;
71     if (isdigit(*str.constp)) {
72 	unsigned long n = strtoul(str.constp, &str.p, 0);
73 	if (n >= __CAP_MAXBITS)
74 	    return -1;
75 	*strp = str.constp;
76 	return n;
77     } else {
78 	int c;
79 	unsigned len;
80 
81 	for (len=0; (c = str.constp[len]); ++len) {
82 	    if (!(isalpha(c) || (c == '_'))) {
83 		break;
84 	    }
85 	}
86 
87 #ifdef GPERF_DOWNCASE
88 	const struct __cap_token_s *token_info;
89 
90 	token_info = __cap_lookup_name(str.constp, len);
91 	if (token_info != NULL) {
92 	    *strp = str.constp + len;
93 	    return token_info->index;
94 	}
95 #else /* ie., ndef GPERF_DOWNCASE */
96 	char const *s;
97 	unsigned n;
98 
99 	for (n = __CAP_BITS; n--; )
100 	    if (_cap_names[n] && (s = namcmp(str.constp, _cap_names[n]))) {
101 		*strp = s;
102 		return n;
103 	    }
104 #endif /* def GPERF_DOWNCASE */
105 
106 	return -1;   	/* No definition available */
107     }
108 }
109 
cap_from_text(const char * str)110 cap_t cap_from_text(const char *str)
111 {
112     cap_t res;
113     int n;
114     unsigned cap_blks;
115 
116     if (str == NULL) {
117 	_cap_debug("bad argument");
118 	errno = EINVAL;
119 	return NULL;
120     }
121 
122     if (!(res = cap_init()))
123 	return NULL;
124 
125     switch (res->head.version) {
126     case _LINUX_CAPABILITY_VERSION_1:
127 	cap_blks = _LINUX_CAPABILITY_U32S_1;
128 	break;
129     case _LINUX_CAPABILITY_VERSION_2:
130 	cap_blks = _LINUX_CAPABILITY_U32S_2;
131 	break;
132     case _LINUX_CAPABILITY_VERSION_3:
133 	cap_blks = _LINUX_CAPABILITY_U32S_3;
134 	break;
135     default:
136 	errno = EINVAL;
137 	return NULL;
138     }
139 
140     _cap_debug("%s", str);
141 
142     for (;;) {
143 	__u32 list[__CAP_BLKS];
144 	char op;
145 	int flags = 0, listed=0;
146 
147 	forceall(list, 0, __CAP_BLKS);
148 
149 	/* skip leading spaces */
150 	while (isspace((unsigned char)*str))
151 	    str++;
152 	if (!*str) {
153 	    _cap_debugcap("e = ", *res, CAP_EFFECTIVE);
154 	    _cap_debugcap("i = ", *res, CAP_INHERITABLE);
155 	    _cap_debugcap("p = ", *res, CAP_PERMITTED);
156 
157 	    return res;
158 	}
159 
160 	/* identify caps specified by this clause */
161 	if (isalnum((unsigned char)*str) || *str == '_') {
162 	    for (;;) {
163 		if (namcmp(str, "all")) {
164 		    str += 3;
165 		    forceall(list, ~0, cap_blks);
166 		} else {
167 		    n = lookupname(&str);
168 		    if (n == -1)
169 			goto bad;
170 		    raise_cap_mask(list, n);
171 		}
172 		if (*str != ',')
173 		    break;
174 		if (!isalnum((unsigned char)*++str) && *str != '_')
175 		    goto bad;
176 	    }
177 	    listed = 1;
178 	} else if (*str == '+' || *str == '-') {
179 	    goto bad;                    /* require a list of capabilities */
180 	} else {
181 	    forceall(list, ~0, cap_blks);
182 	}
183 
184 	/* identify first operation on list of capabilities */
185 	op = *str++;
186 	if (op == '=' && (*str == '+' || *str == '-')) {
187 	    if (!listed)
188 		goto bad;
189 	    op = (*str++ == '+' ? 'P':'M'); /* skip '=' and take next op */
190 	} else if (op != '+' && op != '-' && op != '=')
191 	    goto bad;
192 
193 	/* cycle through list of actions */
194 	do {
195 	    _cap_debug("next char = `%c'", *str);
196 	    if (*str && !isspace(*str)) {
197 		switch (*str++) {    /* Effective, Inheritable, Permitted */
198 		case 'e':
199 		    flags |= LIBCAP_EFF;
200 		    break;
201 		case 'i':
202 		    flags |= LIBCAP_INH;
203 		    break;
204 		case 'p':
205 		    flags |= LIBCAP_PER;
206 		    break;
207 		default:
208 		    goto bad;
209 		}
210 	    } else if (op != '=') {
211 		_cap_debug("only '=' can be followed by space");
212 		goto bad;
213 	    }
214 
215 	    _cap_debug("how to read?");
216 	    switch (op) {               /* how do we interpret the caps? */
217 	    case '=':
218 	    case 'P':                                              /* =+ */
219 	    case 'M':                                              /* =- */
220 		clrbits(res, list, CAP_EFFECTIVE, cap_blks);
221 		clrbits(res, list, CAP_PERMITTED, cap_blks);
222 		clrbits(res, list, CAP_INHERITABLE, cap_blks);
223 		if (op == 'M')
224 		    goto minus;
225 		/* fall through */
226 	    case '+':
227 		if (flags & LIBCAP_EFF)
228 		    setbits(res, list, CAP_EFFECTIVE, cap_blks);
229 		if (flags & LIBCAP_PER)
230 		    setbits(res, list, CAP_PERMITTED, cap_blks);
231 		if (flags & LIBCAP_INH)
232 		    setbits(res, list, CAP_INHERITABLE, cap_blks);
233 		break;
234 	    case '-':
235 	    minus:
236 		if (flags & LIBCAP_EFF)
237 		    clrbits(res, list, CAP_EFFECTIVE, cap_blks);
238 		if (flags & LIBCAP_PER)
239 		    clrbits(res, list, CAP_PERMITTED, cap_blks);
240 		if (flags & LIBCAP_INH)
241 		    clrbits(res, list, CAP_INHERITABLE, cap_blks);
242 		break;
243 	    }
244 
245 	    /* new directive? */
246 	    if (*str == '+' || *str == '-') {
247 		if (!listed) {
248 		    _cap_debug("for + & - must list capabilities");
249 		    goto bad;
250 		}
251 		flags = 0;                       /* reset the flags */
252 		op = *str++;
253 		if (!isalpha(*str))
254 		    goto bad;
255 	    }
256 	} while (*str && !isspace(*str));
257 	_cap_debug("next clause");
258     }
259 
260 bad:
261     cap_free(res);
262     res = NULL;
263     errno = EINVAL;
264     return res;
265 }
266 
267 /*
268  * lookup a capability name and return its numerical value
269  */
cap_from_name(const char * name,cap_value_t * value_p)270 int cap_from_name(const char *name, cap_value_t *value_p)
271 {
272     int n;
273 
274     if (((n = lookupname(&name)) >= 0) && (value_p != NULL)) {
275 	*value_p = (unsigned) n;
276     }
277     return -(n < 0);
278 }
279 
280 /*
281  * Convert a single capability index number into a string representation
282  */
cap_to_name(cap_value_t cap)283 char *cap_to_name(cap_value_t cap)
284 {
285     if ((cap < 0) || (cap >= __CAP_BITS)) {
286 #if UINT_MAX != 4294967295U
287 # error Recompile with correctly sized numeric array
288 #endif
289 	char *tmp, *result;
290 
291 	asprintf(&tmp, "%u", cap);
292 	result = _libcap_strdup(tmp);
293 	free(tmp);
294 
295 	return result;
296     } else {
297 	return _libcap_strdup(_cap_names[cap]);
298     }
299 }
300 
301 /*
302  * Convert an internal representation to a textual one. The textual
303  * representation is stored in static memory. It will be overwritten
304  * on the next occasion that this function is called.
305  */
306 
getstateflags(cap_t caps,int capno)307 static int getstateflags(cap_t caps, int capno)
308 {
309     int f = 0;
310 
311     if (isset_cap(caps, capno, CAP_EFFECTIVE)) {
312 	f |= LIBCAP_EFF;
313     }
314     if (isset_cap(caps, capno, CAP_PERMITTED)) {
315 	f |= LIBCAP_PER;
316     }
317     if (isset_cap(caps, capno, CAP_INHERITABLE)) {
318 	f |= LIBCAP_INH;
319     }
320 
321     return f;
322 }
323 
324 #define CAP_TEXT_BUFFER_ZONE 100
325 
cap_to_text(cap_t caps,ssize_t * length_p)326 char *cap_to_text(cap_t caps, ssize_t *length_p)
327 {
328     char buf[CAP_TEXT_SIZE+CAP_TEXT_BUFFER_ZONE];
329     char *p;
330     int histo[8];
331     int m, t;
332     unsigned n;
333     unsigned cap_maxbits, cap_blks;
334 
335     /* Check arguments */
336     if (!good_cap_t(caps)) {
337 	errno = EINVAL;
338 	return NULL;
339     }
340 
341     switch (caps->head.version) {
342     case _LINUX_CAPABILITY_VERSION_1:
343 	cap_blks = _LINUX_CAPABILITY_U32S_1;
344 	break;
345     case _LINUX_CAPABILITY_VERSION_2:
346 	cap_blks = _LINUX_CAPABILITY_U32S_2;
347 	break;
348     case _LINUX_CAPABILITY_VERSION_3:
349 	cap_blks = _LINUX_CAPABILITY_U32S_3;
350 	break;
351     default:
352 	errno = EINVAL;
353 	return NULL;
354     }
355 
356     cap_maxbits = 32 * cap_blks;
357 
358     _cap_debugcap("e = ", *caps, CAP_EFFECTIVE);
359     _cap_debugcap("i = ", *caps, CAP_INHERITABLE);
360     _cap_debugcap("p = ", *caps, CAP_PERMITTED);
361 
362     memset(histo, 0, sizeof(histo));
363 
364     /* default prevailing state to the upper - unnamed bits */
365     for (n = cap_maxbits-1; n > __CAP_BITS; n--)
366 	histo[getstateflags(caps, n)]++;
367 
368     /* find which combination of capability sets shares the most bits
369        we bias to preferring non-set (m=0) with the >= 0 test. Failing
370        to do this causes strange things to happen with older systems
371        that don't know about bits 32+. */
372     for (m=t=7; t--; )
373 	if (histo[t] >= histo[m])
374 	    m = t;
375 
376     /* capture remaining bits - selecting m from only the unnamed bits,
377        we maximize the likelihood that we won't see numeric capability
378        values in the text output. */
379     while (n--)
380 	histo[getstateflags(caps, n)]++;
381 
382     /* blank is not a valid capability set */
383     p = sprintf(buf, "=%s%s%s",
384 		(m & LIBCAP_EFF) ? "e" : "",
385 		(m & LIBCAP_INH) ? "i" : "",
386 		(m & LIBCAP_PER) ? "p" : "" ) + buf;
387 
388     for (t = 8; t--; )
389 	if (t != m && histo[t]) {
390 	    *p++ = ' ';
391 	    for (n = 0; n < cap_maxbits; n++)
392 		if (getstateflags(caps, n) == t) {
393 		    char *this_cap_name;
394 
395 		    this_cap_name = cap_to_name(n);
396 		    if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) {
397 			cap_free(this_cap_name);
398 			errno = ERANGE;
399 			return NULL;
400 		    }
401 		    p += sprintf(p, "%s,", this_cap_name);
402 		    cap_free(this_cap_name);
403 		}
404 	    p--;
405 	    n = t & ~m;
406 	    if (n)
407 		p += sprintf(p, "+%s%s%s",
408 			     (n & LIBCAP_EFF) ? "e" : "",
409 			     (n & LIBCAP_INH) ? "i" : "",
410 			     (n & LIBCAP_PER) ? "p" : "");
411 	    n = ~t & m;
412 	    if (n)
413 		p += sprintf(p, "-%s%s%s",
414 			     (n & LIBCAP_EFF) ? "e" : "",
415 			     (n & LIBCAP_INH) ? "i" : "",
416 			     (n & LIBCAP_PER) ? "p" : "");
417 	    if (p - buf > CAP_TEXT_SIZE) {
418 		errno = ERANGE;
419 		return NULL;
420 	    }
421 	}
422 
423     _cap_debug("%s", buf);
424     if (length_p) {
425 	*length_p = p - buf;
426     }
427 
428     return (_libcap_strdup(buf));
429 }
430