1 /*
2 * Copyright (c) 1997,2007-8 Andrew G. Morgan <morgan@kernel.org>
3 *
4 * This sets/verifies the capabilities of a given file.
5 */
6
7 #include <errno.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <sys/capability.h>
12 #include <unistd.h>
13
usage(void)14 static void usage(void)
15 {
16 fprintf(stderr,
17 "usage: setcap [-q] [-v] (-r|-|<caps>) <filename> "
18 "[ ... (-r|-|<capsN>) <filenameN> ]\n"
19 "\n"
20 " Note <filename> must be a regular (non-symlink) file.\n"
21 );
22 exit(1);
23 }
24
25 #define MAXCAP 2048
26
read_caps(int quiet,const char * filename,char * buffer)27 static int read_caps(int quiet, const char *filename, char *buffer)
28 {
29 int i = MAXCAP;
30
31 if (!quiet) {
32 fprintf(stderr, "Please enter caps for file [empty line to end]:\n");
33 }
34 while (i > 0) {
35 int j = read(STDIN_FILENO, buffer, i);
36
37 if (j < 0) {
38 fprintf(stderr, "\n[Error - aborting]\n");
39 exit(1);
40 }
41
42 if (j==0 || buffer[0] == '\n') {
43 /* we're done */
44 break;
45 }
46
47 /* move on... */
48
49 i -= j;
50 buffer += j;
51 }
52
53 /* <NUL> terminate */
54 buffer[0] = '\0';
55
56 return (i < MAXCAP ? 0:-1);
57 }
58
main(int argc,char ** argv)59 int main(int argc, char **argv)
60 {
61 int tried_to_cap_setfcap = 0;
62 char buffer[MAXCAP+1];
63 int retval, quiet=0, verify=0;
64 cap_t mycaps;
65 cap_value_t capflag;
66
67 if (argc < 3) {
68 usage();
69 }
70
71 mycaps = cap_get_proc();
72 if (mycaps == NULL) {
73 fprintf(stderr, "warning - unable to get process capabilities"
74 " (old libcap?)\n");
75 }
76
77 while (--argc > 0) {
78 const char *text;
79 cap_t cap_d;
80
81 if (!strcmp(*++argv, "-q")) {
82 quiet = 1;
83 continue;
84 }
85 if (!strcmp(*argv, "-v")) {
86 verify = 1;
87 continue;
88 }
89
90 if (!strcmp(*argv, "-r")) {
91 cap_d = NULL;
92 } else {
93 if (!strcmp(*argv,"-")) {
94 retval = read_caps(quiet, *argv, buffer);
95 if (retval)
96 usage();
97 text = buffer;
98 } else {
99 text = *argv;
100 }
101
102 cap_d = cap_from_text(text);
103 if (cap_d == NULL) {
104 perror("fatal error");
105 usage();
106 }
107 #ifdef DEBUG
108 {
109 ssize_t length;
110 const char *result;
111
112 result = cap_to_text(cap_d, &length);
113 fprintf(stderr, "caps set to: [%s]\n", result);
114 }
115 #endif
116 }
117
118 if (--argc <= 0)
119 usage();
120 /*
121 * Set the filesystem capability for this file.
122 */
123 if (verify) {
124 cap_t cap_on_file;
125 int cmp;
126
127 if (cap_d == NULL) {
128 cap_d = cap_from_text("=");
129 }
130
131 cap_on_file = cap_get_file(*++argv);
132
133 if (cap_on_file == NULL) {
134 cap_on_file = cap_from_text("=");
135 }
136
137 cmp = cap_compare(cap_on_file, cap_d);
138 cap_free(cap_on_file);
139
140 if (cmp != 0) {
141 if (!quiet) {
142 printf("%s differs in [%s%s%s]\n", *argv,
143 CAP_DIFFERS(cmp, CAP_PERMITTED) ? "p" : "",
144 CAP_DIFFERS(cmp, CAP_INHERITABLE) ? "i" : "",
145 CAP_DIFFERS(cmp, CAP_EFFECTIVE) ? "e" : "");
146 }
147 exit(1);
148 }
149 if (!quiet) {
150 printf("%s: OK\n", *argv);
151 }
152 } else {
153 if (!tried_to_cap_setfcap) {
154 capflag = CAP_SETFCAP;
155
156 /*
157 * Raise the effective CAP_SETFCAP.
158 */
159 if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_SET)
160 != 0) {
161 perror("unable to manipulate CAP_SETFCAP - "
162 "try a newer libcap?");
163 exit(1);
164 }
165 if (cap_set_proc(mycaps) != 0) {
166 perror("unable to set CAP_SETFCAP effective capability");
167 exit(1);
168 }
169 tried_to_cap_setfcap = 1;
170 }
171 retval = cap_set_file(*++argv, cap_d);
172 if (retval != 0) {
173 int explained = 0;
174 int oerrno = errno;
175 #ifdef linux
176 cap_value_t cap;
177 cap_flag_value_t per_state;
178
179 for (cap = 0;
180 cap_get_flag(cap_d, cap, CAP_PERMITTED, &per_state) != -1;
181 cap++) {
182 cap_flag_value_t inh_state, eff_state;
183
184 cap_get_flag(cap_d, cap, CAP_INHERITABLE, &inh_state);
185 cap_get_flag(cap_d, cap, CAP_EFFECTIVE, &eff_state);
186 if ((inh_state | per_state) != eff_state) {
187 fprintf(stderr, "NOTE: Under Linux, effective file capabilities must either be empty, or\n"
188 " exactly match the union of selected permitted and inheritable bits.\n");
189 explained = 1;
190 break;
191 }
192 }
193 #endif /* def linux */
194
195 fprintf(stderr,
196 "Failed to set capabilities on file `%s' (%s)\n",
197 argv[0], strerror(oerrno));
198 if (!explained) {
199 usage();
200 }
201 }
202 }
203 if (cap_d) {
204 cap_free(cap_d);
205 }
206 }
207
208 exit(0);
209 }
210