summaryrefslogtreecommitdiff
path: root/libcap/cap_flag.c
blob: 52ec3b32e0fd1c5a9249a50f6e8e99f1aef3bf26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * Copyright (c) 1997-8,2008 Andrew G. Morgan <morgan@kernel.org>
 *
 * This file deals with flipping of capabilities on internal
 * capability sets as specified by POSIX.1e (formerlly, POSIX 6).
 */

#include "libcap.h"

/*
 * Return the state of a specified capability flag.  The state is
 * returned as the contents of *raised.  The capability is from one of
 * the sets stored in cap_d as specified by set and value
 */

int cap_get_flag(cap_t cap_d, cap_value_t value, cap_flag_t set,
		 cap_flag_value_t *raised)
{
    /*
     * Do we have a set and a place to store its value?
     * Is it a known capability?
     */

    if (raised && good_cap_t(cap_d) && value >= 0 && value < __CAP_BITS
	&& set >= 0 && set < NUMBER_OF_CAP_SETS) {
	*raised = isset_cap(cap_d,value,set) ? CAP_SET:CAP_CLEAR;
	return 0;
    } else {
	_cap_debug("invalid arguments");
	errno = EINVAL;
	return -1;
    }
}

/*
 * raise/lower a selection of capabilities
 */

int cap_set_flag(cap_t cap_d, cap_flag_t set,
		 int no_values, const cap_value_t *array_values,
		 cap_flag_value_t raise)
{
    /*
     * Do we have a set and a place to store its value?
     * Is it a known capability?
     */

    if (good_cap_t(cap_d) && no_values > 0 && no_values <= __CAP_BITS
	&& (set >= 0) && (set < NUMBER_OF_CAP_SETS)
	&& (raise == CAP_SET || raise == CAP_CLEAR) ) {
	int i;
	for (i=0; i<no_values; ++i) {
	    if (array_values[i] < 0 || array_values[i] >= __CAP_BITS) {
		_cap_debug("weird capability (%d) - skipped", array_values[i]);
	    } else {
		int value = array_values[i];

		if (raise == CAP_SET) {
		    cap_d->raise_cap(value,set);
		} else {
		    cap_d->lower_cap(value,set);
		}
	    }
	}
	return 0;

    } else {

	_cap_debug("invalid arguments");
	errno = EINVAL;
	return -1;

    }
}

/*
 *  Reset the capability to be empty (nothing raised)
 */

int cap_clear(cap_t cap_d)
{
    if (good_cap_t(cap_d)) {

	memset(&(cap_d->u), 0, sizeof(cap_d->u));
	return 0;

    } else {

	_cap_debug("invalid pointer");
	errno = EINVAL;
	return -1;

    }
}

/*
 *  Reset the all of the capability bits for one of the flag sets
 */

int cap_clear_flag(cap_t cap_d, cap_flag_t flag)
{
    switch (flag) {
    case CAP_EFFECTIVE:
    case CAP_PERMITTED:
    case CAP_INHERITABLE:
	if (good_cap_t(cap_d)) {
	    unsigned i;

	    for (i=0; i<_LIBCAP_CAPABILITY_U32S; i++) {
		cap_d->u[i].flat[flag] = 0;
	    }
	    return 0;
	}
	/*
	 * fall through
	 */

    default:
	_cap_debug("invalid pointer");
	errno = EINVAL;
	return -1;
    }
}

/*
 * Compare two capability sets
 */

int cap_compare(cap_t a, cap_t b)
{
    unsigned i;
    int result;

    if (!(good_cap_t(a) && good_cap_t(b))) {
	_cap_debug("invalid arguments");
	errno = EINVAL;
	return -1;
    }

    for (i=0, result=0; i<_LIBCAP_CAPABILITY_U32S; i++) {
	result |=
	    ((a->u[i].flat[CAP_EFFECTIVE] != b->u[i].flat[CAP_EFFECTIVE])
	     ? LIBCAP_EFF : 0)
	    | ((a->u[i].flat[CAP_INHERITABLE] != b->u[i].flat[CAP_INHERITABLE])
	       ? LIBCAP_INH : 0)
	    | ((a->u[i].flat[CAP_PERMITTED] != b->u[i].flat[CAP_PERMITTED])
	       ? LIBCAP_PER : 0);
    }
    return result;
}