1255219Spjd/*-
2255219Spjd * Copyright (c) 2013 FreeBSD Foundation
3255219Spjd * All rights reserved.
4255219Spjd *
5255219Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
6255219Spjd * the FreeBSD Foundation.
7255219Spjd *
8255219Spjd * Redistribution and use in source and binary forms, with or without
9255219Spjd * modification, are permitted provided that the following conditions
10255219Spjd * are met:
11255219Spjd * 1. Redistributions of source code must retain the above copyright
12255219Spjd *    notice, this list of conditions and the following disclaimer.
13255219Spjd * 2. Redistributions in binary form must reproduce the above copyright
14255219Spjd *    notice, this list of conditions and the following disclaimer in the
15255219Spjd *    documentation and/or other materials provided with the distribution.
16255219Spjd *
17255219Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18255219Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19255219Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20255219Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21255219Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22255219Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23255219Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24255219Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25255219Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26255219Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27255219Spjd * SUCH DAMAGE.
28255219Spjd */
29255219Spjd
30255219Spjd#include <sys/cdefs.h>
31255219Spjd__FBSDID("$FreeBSD$");
32255219Spjd
33258324Spjd/*
34258324Spjd * Note that this file is compiled into the kernel and into libc.
35258324Spjd */
36258324Spjd
37255219Spjd#ifdef _KERNEL
38255219Spjd#include <sys/types.h>
39255219Spjd#include <sys/capability.h>
40255219Spjd#include <sys/systm.h>
41255219Spjd
42255219Spjd#include <machine/stdarg.h>
43255219Spjd#else	/* !_KERNEL */
44255219Spjd#include <sys/types.h>
45255219Spjd#include <sys/capability.h>
46255219Spjd
47255219Spjd#include <assert.h>
48255219Spjd#include <stdarg.h>
49255219Spjd#include <stdbool.h>
50255219Spjd#include <stdint.h>
51255219Spjd#include <string.h>
52255219Spjd#endif
53255219Spjd
54255219Spjd#ifdef _KERNEL
55255219Spjd#define	assert(exp)	KASSERT((exp), ("%s:%u", __func__, __LINE__))
56255219Spjd#endif
57255219Spjd
58255372Spjd#define	CAPARSIZE_MIN	(CAP_RIGHTS_VERSION_00 + 2)
59255372Spjd#define	CAPARSIZE_MAX	(CAP_RIGHTS_VERSION + 2)
60255372Spjd
61255372Spjdstatic __inline int
62255219Spjdright_to_index(uint64_t right)
63255219Spjd{
64255219Spjd	static const int bit2idx[] = {
65255219Spjd		-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
66255219Spjd		4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
67255219Spjd	};
68255219Spjd	int idx;
69255219Spjd
70255219Spjd	idx = CAPIDXBIT(right);
71255372Spjd	assert(idx >= 0 && idx < sizeof(bit2idx) / sizeof(bit2idx[0]));
72255372Spjd	return (bit2idx[idx]);
73255219Spjd}
74255219Spjd
75255219Spjdstatic void
76255219Spjdcap_rights_vset(cap_rights_t *rights, va_list ap)
77255219Spjd{
78255219Spjd	uint64_t right;
79255372Spjd	int i, n;
80255219Spjd
81255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
82255219Spjd
83255219Spjd	n = CAPARSIZE(rights);
84255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
85255219Spjd
86255219Spjd	for (;;) {
87255219Spjd		right = (uint64_t)va_arg(ap, unsigned long long);
88255219Spjd		if (right == 0)
89255219Spjd			break;
90255219Spjd		assert(CAPRVER(right) == 0);
91255219Spjd		i = right_to_index(right);
92255372Spjd		assert(i >= 0);
93255219Spjd		assert(i < n);
94255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
95255219Spjd		rights->cr_rights[i] |= right;
96255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
97255219Spjd	}
98255219Spjd}
99255219Spjd
100255219Spjdstatic void
101255219Spjdcap_rights_vclear(cap_rights_t *rights, va_list ap)
102255219Spjd{
103255219Spjd	uint64_t right;
104255372Spjd	int i, n;
105255219Spjd
106255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
107255219Spjd
108255219Spjd	n = CAPARSIZE(rights);
109255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
110255219Spjd
111255219Spjd	for (;;) {
112255219Spjd		right = (uint64_t)va_arg(ap, unsigned long long);
113255219Spjd		if (right == 0)
114255219Spjd			break;
115255219Spjd		assert(CAPRVER(right) == 0);
116255219Spjd		i = right_to_index(right);
117255372Spjd		assert(i >= 0);
118255219Spjd		assert(i < n);
119255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
120255219Spjd		rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL);
121255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
122255219Spjd	}
123255219Spjd}
124255219Spjd
125255219Spjdstatic bool
126255219Spjdcap_rights_is_vset(const cap_rights_t *rights, va_list ap)
127255219Spjd{
128255219Spjd	uint64_t right;
129255372Spjd	int i, n;
130255219Spjd
131255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
132255219Spjd
133255219Spjd	n = CAPARSIZE(rights);
134255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
135255219Spjd
136255219Spjd	for (;;) {
137255219Spjd		right = (uint64_t)va_arg(ap, unsigned long long);
138255219Spjd		if (right == 0)
139255219Spjd			break;
140255219Spjd		assert(CAPRVER(right) == 0);
141255219Spjd		i = right_to_index(right);
142255372Spjd		assert(i >= 0);
143255219Spjd		assert(i < n);
144255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
145255219Spjd		if ((rights->cr_rights[i] & right) != right)
146255219Spjd			return (false);
147255219Spjd	}
148255219Spjd
149255219Spjd	return (true);
150255219Spjd}
151255219Spjd
152255219Spjdcap_rights_t *
153255219Spjd__cap_rights_init(int version, cap_rights_t *rights, ...)
154255219Spjd{
155255219Spjd	unsigned int n;
156255219Spjd	va_list ap;
157255219Spjd
158255219Spjd	assert(version == CAP_RIGHTS_VERSION_00);
159255219Spjd
160255219Spjd	n = version + 2;
161255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
162255219Spjd	memset(rights->cr_rights, 0, sizeof(rights->cr_rights[0]) * n);
163255219Spjd	CAP_NONE(rights);
164255219Spjd	va_start(ap, rights);
165255219Spjd	cap_rights_vset(rights, ap);
166255219Spjd	va_end(ap);
167255219Spjd
168255219Spjd	return (rights);
169255219Spjd}
170255219Spjd
171258324Spjdcap_rights_t *
172255219Spjd__cap_rights_set(cap_rights_t *rights, ...)
173255219Spjd{
174255219Spjd	va_list ap;
175255219Spjd
176255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
177255219Spjd
178255219Spjd	va_start(ap, rights);
179255219Spjd	cap_rights_vset(rights, ap);
180255219Spjd	va_end(ap);
181258324Spjd
182258324Spjd	return (rights);
183255219Spjd}
184255219Spjd
185258324Spjdcap_rights_t *
186255219Spjd__cap_rights_clear(cap_rights_t *rights, ...)
187255219Spjd{
188255219Spjd	va_list ap;
189255219Spjd
190255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
191255219Spjd
192255219Spjd	va_start(ap, rights);
193255219Spjd	cap_rights_vclear(rights, ap);
194255219Spjd	va_end(ap);
195258324Spjd
196258324Spjd	return (rights);
197255219Spjd}
198255219Spjd
199255219Spjdbool
200255219Spjd__cap_rights_is_set(const cap_rights_t *rights, ...)
201255219Spjd{
202255219Spjd	va_list ap;
203255219Spjd	bool ret;
204255219Spjd
205255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
206255219Spjd
207255219Spjd	va_start(ap, rights);
208255219Spjd	ret = cap_rights_is_vset(rights, ap);
209255219Spjd	va_end(ap);
210255219Spjd
211255219Spjd	return (ret);
212255219Spjd}
213255219Spjd
214255219Spjdbool
215255219Spjdcap_rights_is_valid(const cap_rights_t *rights)
216255219Spjd{
217255219Spjd	cap_rights_t allrights;
218255372Spjd	int i, j;
219255219Spjd
220255219Spjd	if (CAPVER(rights) != CAP_RIGHTS_VERSION_00)
221255219Spjd		return (false);
222255372Spjd	if (CAPARSIZE(rights) < CAPARSIZE_MIN ||
223255372Spjd	    CAPARSIZE(rights) > CAPARSIZE_MAX) {
224255372Spjd		return (false);
225255372Spjd	}
226255219Spjd	CAP_ALL(&allrights);
227255219Spjd	if (!cap_rights_contains(&allrights, rights))
228255219Spjd		return (false);
229255219Spjd	for (i = 0; i < CAPARSIZE(rights); i++) {
230255219Spjd		j = right_to_index(rights->cr_rights[i]);
231255219Spjd		if (i != j)
232255219Spjd			return (false);
233255219Spjd		if (i > 0) {
234255219Spjd			if (CAPRVER(rights->cr_rights[i]) != 0)
235255219Spjd				return (false);
236255219Spjd		}
237255219Spjd	}
238255219Spjd
239255219Spjd	return (true);
240255219Spjd}
241255219Spjd
242258324Spjdcap_rights_t *
243255219Spjdcap_rights_merge(cap_rights_t *dst, const cap_rights_t *src)
244255219Spjd{
245255219Spjd	unsigned int i, n;
246255219Spjd
247255219Spjd	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
248255219Spjd	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
249255219Spjd	assert(CAPVER(dst) == CAPVER(src));
250255219Spjd	assert(cap_rights_is_valid(src));
251255219Spjd	assert(cap_rights_is_valid(dst));
252255219Spjd
253255219Spjd	n = CAPARSIZE(dst);
254255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
255255219Spjd
256255219Spjd	for (i = 0; i < n; i++)
257255219Spjd		dst->cr_rights[i] |= src->cr_rights[i];
258255219Spjd
259255219Spjd	assert(cap_rights_is_valid(src));
260255219Spjd	assert(cap_rights_is_valid(dst));
261258324Spjd
262258324Spjd	return (dst);
263255219Spjd}
264255219Spjd
265258324Spjdcap_rights_t *
266255219Spjdcap_rights_remove(cap_rights_t *dst, const cap_rights_t *src)
267255219Spjd{
268255219Spjd	unsigned int i, n;
269255219Spjd
270255219Spjd	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
271255219Spjd	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
272255219Spjd	assert(CAPVER(dst) == CAPVER(src));
273255219Spjd	assert(cap_rights_is_valid(src));
274255219Spjd	assert(cap_rights_is_valid(dst));
275255219Spjd
276255219Spjd	n = CAPARSIZE(dst);
277255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
278255219Spjd
279255219Spjd	for (i = 0; i < n; i++) {
280255219Spjd		dst->cr_rights[i] &=
281255219Spjd		    ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL);
282255219Spjd	}
283255219Spjd
284255219Spjd	assert(cap_rights_is_valid(src));
285255219Spjd	assert(cap_rights_is_valid(dst));
286258324Spjd
287258324Spjd	return (dst);
288255219Spjd}
289255219Spjd
290255219Spjdbool
291255219Spjdcap_rights_contains(const cap_rights_t *big, const cap_rights_t *little)
292255219Spjd{
293255219Spjd	unsigned int i, n;
294255219Spjd
295255219Spjd	assert(CAPVER(big) == CAP_RIGHTS_VERSION_00);
296255219Spjd	assert(CAPVER(little) == CAP_RIGHTS_VERSION_00);
297255219Spjd	assert(CAPVER(big) == CAPVER(little));
298255219Spjd
299255219Spjd	n = CAPARSIZE(big);
300255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
301255219Spjd
302255219Spjd	for (i = 0; i < n; i++) {
303255219Spjd		if ((big->cr_rights[i] & little->cr_rights[i]) !=
304255219Spjd		    little->cr_rights[i]) {
305255219Spjd			return (false);
306255219Spjd		}
307255219Spjd	}
308255219Spjd
309255219Spjd	return (true);
310255219Spjd}
311