1/*
2 * Copyright (c) 1997,2007 Andrew G Morgan <morgan@kernel.org>
3 *
4 * This file deals with setting capabilities on files.
5 */
6
7#include <sys/types.h>
8#include <sys/xattr.h>
9#include <byteswap.h>
10#include <sys/stat.h>
11#include <unistd.h>
12
13#include <linux/xattr.h>
14
15#define XATTR_SECURITY_PREFIX "security."
16
17#include "libcap.h"
18
19#ifdef VFS_CAP_U32
20
21#if VFS_CAP_U32 != __CAP_BLKS
22# error VFS representation of capabilities is not the same size as kernel
23#endif
24
25#if __BYTE_ORDER == __BIG_ENDIAN
26#define FIXUP_32BITS(x) bswap_32(x)
27#else
28#define FIXUP_32BITS(x) (x)
29#endif
30
31static cap_t _fcaps_load(struct vfs_cap_data *rawvfscap, cap_t result,
32			 int bytes)
33{
34    __u32 magic_etc;
35    unsigned tocopy, i;
36
37    magic_etc = FIXUP_32BITS(rawvfscap->magic_etc);
38    switch (magic_etc & VFS_CAP_REVISION_MASK) {
39#ifdef VFS_CAP_REVISION_1
40    case VFS_CAP_REVISION_1:
41	tocopy = VFS_CAP_U32_1;
42	bytes -= XATTR_CAPS_SZ_1;
43	break;
44#endif
45
46#ifdef VFS_CAP_REVISION_2
47    case VFS_CAP_REVISION_2:
48	tocopy = VFS_CAP_U32_2;
49	bytes -= XATTR_CAPS_SZ_2;
50	break;
51#endif
52
53    default:
54	cap_free(result);
55	result = NULL;
56	return result;
57    }
58
59    /*
60     * Verify that we loaded exactly the right number of bytes
61     */
62    if (bytes != 0) {
63	cap_free(result);
64	result = NULL;
65	return result;
66    }
67
68    for (i=0; i < tocopy; i++) {
69	result->u[i].flat[CAP_INHERITABLE]
70	    = FIXUP_32BITS(rawvfscap->data[i].inheritable);
71	result->u[i].flat[CAP_PERMITTED]
72	    = FIXUP_32BITS(rawvfscap->data[i].permitted);
73	if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
74	    result->u[i].flat[CAP_EFFECTIVE]
75		= result->u[i].flat[CAP_INHERITABLE]
76		| result->u[i].flat[CAP_PERMITTED];
77	}
78    }
79    while (i < __CAP_BLKS) {
80	result->u[i].flat[CAP_INHERITABLE]
81	    = result->u[i].flat[CAP_PERMITTED]
82	    = result->u[i].flat[CAP_EFFECTIVE] = 0;
83	i++;
84    }
85
86    return result;
87}
88
89static int _fcaps_save(struct vfs_cap_data *rawvfscap, cap_t cap_d,
90		       int *bytes_p)
91{
92    __u32 eff_not_zero, magic;
93    unsigned tocopy, i;
94
95    if (!good_cap_t(cap_d)) {
96	errno = EINVAL;
97	return -1;
98    }
99
100    switch (cap_d->head.version) {
101#ifdef _LINUX_CAPABILITY_VERSION_1
102    case _LINUX_CAPABILITY_VERSION_1:
103	magic = VFS_CAP_REVISION_1;
104	tocopy = VFS_CAP_U32_1;
105	*bytes_p = XATTR_CAPS_SZ_1;
106	break;
107#endif
108
109#ifdef _LINUX_CAPABILITY_VERSION_2
110    case _LINUX_CAPABILITY_VERSION_2:
111	magic = VFS_CAP_REVISION_2;
112	tocopy = VFS_CAP_U32_2;
113	*bytes_p = XATTR_CAPS_SZ_2;
114	break;
115#endif
116
117#ifdef _LINUX_CAPABILITY_VERSION_3
118    case _LINUX_CAPABILITY_VERSION_3:
119	magic = VFS_CAP_REVISION_2;
120	tocopy = VFS_CAP_U32_2;
121	*bytes_p = XATTR_CAPS_SZ_2;
122	break;
123#endif
124
125    default:
126	errno = EINVAL;
127	return -1;
128    }
129
130    _cap_debug("setting named file capabilities");
131
132    for (eff_not_zero = 0, i = 0; i < tocopy; i++) {
133	eff_not_zero |= cap_d->u[i].flat[CAP_EFFECTIVE];
134    }
135    while (i < __CAP_BLKS) {
136	if ((cap_d->u[i].flat[CAP_EFFECTIVE]
137	     || cap_d->u[i].flat[CAP_INHERITABLE]
138	     || cap_d->u[i].flat[CAP_PERMITTED])) {
139	    /*
140	     * System does not support these capabilities
141	     */
142	    errno = EINVAL;
143	    return -1;
144	}
145	i++;
146    }
147
148    for (i=0; i < tocopy; i++) {
149	rawvfscap->data[i].permitted
150	    = FIXUP_32BITS(cap_d->u[i].flat[CAP_PERMITTED]);
151	rawvfscap->data[i].inheritable
152	    = FIXUP_32BITS(cap_d->u[i].flat[CAP_INHERITABLE]);
153
154	if (eff_not_zero
155	    && ((~(cap_d->u[i].flat[CAP_EFFECTIVE]))
156		& (cap_d->u[i].flat[CAP_PERMITTED]
157		   | cap_d->u[i].flat[CAP_INHERITABLE]))) {
158	    errno = EINVAL;
159	    return -1;
160	}
161    }
162
163    if (eff_not_zero == 0) {
164	rawvfscap->magic_etc = FIXUP_32BITS(magic);
165    } else {
166	rawvfscap->magic_etc = FIXUP_32BITS(magic|VFS_CAP_FLAGS_EFFECTIVE);
167    }
168
169    return 0;      /* success */
170}
171
172/*
173 * Get the capabilities of an open file, as specified by its file
174 * descriptor.
175 */
176
177cap_t cap_get_fd(int fildes)
178{
179    cap_t result;
180
181    /* allocate a new capability set */
182    result = cap_init();
183    if (result) {
184	struct vfs_cap_data rawvfscap;
185	int sizeofcaps;
186
187	_cap_debug("getting fildes capabilities");
188
189	/* fill the capability sets via a system call */
190	sizeofcaps = fgetxattr(fildes, XATTR_NAME_CAPS,
191			       &rawvfscap, sizeof(rawvfscap));
192	if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) {
193	    cap_free(result);
194	    result = NULL;
195	} else {
196	    result = _fcaps_load(&rawvfscap, result, sizeofcaps);
197	}
198    }
199
200    return result;
201}
202
203/*
204 * Get the capabilities from a named file.
205 */
206
207cap_t cap_get_file(const char *filename)
208{
209    cap_t result;
210
211    /* allocate a new capability set */
212    result = cap_init();
213    if (result) {
214	struct vfs_cap_data rawvfscap;
215	int sizeofcaps;
216
217	_cap_debug("getting filename capabilities");
218
219	/* fill the capability sets via a system call */
220	sizeofcaps = getxattr(filename, XATTR_NAME_CAPS,
221			      &rawvfscap, sizeof(rawvfscap));
222	if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) {
223	    cap_free(result);
224	    result = NULL;
225	} else {
226	    result = _fcaps_load(&rawvfscap, result, sizeofcaps);
227	}
228    }
229
230    return result;
231}
232
233/*
234 * Set the capabilities of an open file, as specified by its file
235 * descriptor.
236 */
237
238int cap_set_fd(int fildes, cap_t cap_d)
239{
240    struct vfs_cap_data rawvfscap;
241    int sizeofcaps;
242    struct stat buf;
243
244    if (fstat(fildes, &buf) != 0) {
245	_cap_debug("unable to stat file descriptor %d", fildes);
246	return -1;
247    }
248    if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) {
249	_cap_debug("file descriptor %d for non-regular file", fildes);
250	errno = EINVAL;
251	return -1;
252    }
253
254    if (cap_d == NULL) {
255	_cap_debug("deleting fildes capabilities");
256	return fremovexattr(fildes, XATTR_NAME_CAPS);
257    } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) {
258	return -1;
259    }
260
261    _cap_debug("setting fildes capabilities");
262
263    return fsetxattr(fildes, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0);
264}
265
266/*
267 * Set the capabilities of a named file.
268 */
269
270int cap_set_file(const char *filename, cap_t cap_d)
271{
272    struct vfs_cap_data rawvfscap;
273    int sizeofcaps;
274    struct stat buf;
275
276    if (lstat(filename, &buf) != 0) {
277	_cap_debug("unable to stat file [%s]", filename);
278	return -1;
279    }
280    if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) {
281	_cap_debug("file [%s] is not a regular file", filename);
282	errno = EINVAL;
283	return -1;
284    }
285
286    if (cap_d == NULL) {
287	_cap_debug("removing filename capabilities");
288	return removexattr(filename, XATTR_NAME_CAPS);
289    } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) {
290	return -1;
291    }
292
293    _cap_debug("setting filename capabilities");
294    return setxattr(filename, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0);
295}
296
297#else /* ie. ndef VFS_CAP_U32 */
298
299cap_t cap_get_fd(int fildes)
300{
301    errno = EINVAL;
302    return NULL;
303}
304
305cap_t cap_get_file(const char *filename)
306{
307    errno = EINVAL;
308    return NULL;
309}
310
311int cap_set_fd(int fildes, cap_t cap_d)
312{
313    errno = EINVAL;
314    return -1;
315}
316
317int cap_set_file(const char *filename, cap_t cap_d)
318{
319    errno = EINVAL;
320    return -1;
321}
322
323#endif /* def VFS_CAP_U32 */
324