]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/caps.c
Don't hard depend on capability.h and libcap
[mirror_lxc.git] / src / lxc / caps.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #define _GNU_SOURCE
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <limits.h>
29 #include <sys/prctl.h>
30 #include <errno.h>
31
32 #include "config.h"
33 #include "log.h"
34
35 lxc_log_define(lxc_caps, lxc);
36
37 #if HAVE_SYS_CAPABILITY_H
38 #include <sys/capability.h>
39
40 int lxc_caps_reset(void)
41 {
42 cap_t cap = cap_init();
43 int ret = 0;
44
45 if (!cap) {
46 ERROR("cap_init() failed : %m");
47 return -1;
48 }
49
50 if (cap_set_proc(cap)) {
51 ERROR("cap_set_proc() failed : %m");
52 ret = -1;
53 }
54
55 cap_free(cap);
56 return ret;
57 }
58
59 int lxc_caps_down(void)
60 {
61 cap_t caps;
62 int ret;
63
64 /* when we are run as root, we don't want to play
65 * with the capabilities */
66 if (!getuid())
67 return 0;
68
69 caps = cap_get_proc();
70 if (!caps) {
71 ERROR("failed to cap_get_proc: %m");
72 return -1;
73 }
74
75 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
76 if (ret) {
77 ERROR("failed to cap_clear_flag: %m");
78 goto out;
79 }
80
81 ret = cap_set_proc(caps);
82 if (ret) {
83 ERROR("failed to cap_set_proc: %m");
84 goto out;
85 }
86
87 out:
88 cap_free(caps);
89 return 0;
90 }
91
92 int lxc_caps_up(void)
93 {
94 cap_t caps;
95 cap_value_t cap;
96 int ret;
97
98 /* when we are run as root, we don't want to play
99 * with the capabilities */
100 if (!getuid())
101 return 0;
102
103 caps = cap_get_proc();
104 if (!caps) {
105 ERROR("failed to cap_get_proc: %m");
106 return -1;
107 }
108
109 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
110
111 cap_flag_value_t flag;
112
113 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
114 if (ret) {
115 if (errno == EINVAL) {
116 INFO("Last supported cap was %d\n", cap-1);
117 break;
118 } else {
119 ERROR("failed to cap_get_flag: %m");
120 goto out;
121 }
122 }
123
124 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
125 if (ret) {
126 ERROR("failed to cap_set_flag: %m");
127 goto out;
128 }
129 }
130
131 ret = cap_set_proc(caps);
132 if (ret) {
133 ERROR("failed to cap_set_proc: %m");
134 goto out;
135 }
136
137 out:
138 cap_free(caps);
139 return 0;
140 }
141
142 int lxc_caps_init(void)
143 {
144 uid_t uid = getuid();
145 gid_t gid = getgid();
146 uid_t euid = geteuid();
147
148 if (!uid) {
149 INFO("command is run as 'root'");
150 return 0;
151 }
152
153 if (uid && !euid) {
154 INFO("command is run as setuid root (uid : %d)", uid);
155
156 if (prctl(PR_SET_KEEPCAPS, 1)) {
157 ERROR("failed to 'PR_SET_KEEPCAPS': %m");
158 return -1;
159 }
160
161 if (setresgid(gid, gid, gid)) {
162 ERROR("failed to change gid to '%d': %m", gid);
163 return -1;
164 }
165
166 if (setresuid(uid, uid, uid)) {
167 ERROR("failed to change uid to '%d': %m", uid);
168 return -1;
169 }
170
171 if (lxc_caps_up()) {
172 ERROR("failed to restore capabilities: %m");
173 return -1;
174 }
175 }
176
177 if (uid == euid)
178 INFO("command is run as user '%d'", uid);
179
180 return 0;
181 }
182
183 static int _real_caps_last_cap(void)
184 {
185 int fd;
186 int result = -1;
187
188 /* try to get the maximum capability over the kernel
189 * interface introduced in v3.2 */
190 fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY);
191 if (fd >= 0) {
192 char buf[32];
193 char *ptr;
194 int n;
195
196 if ((n = read(fd, buf, 31)) >= 0) {
197 buf[n] = '\0';
198 result = strtol(buf, &ptr, 10);
199 if (!ptr || (*ptr != '\0' && *ptr != '\n') ||
200 result == LONG_MIN || result == LONG_MAX)
201 result = -1;
202 }
203
204 close(fd);
205 }
206
207 /* try to get it manually by trying to get the status of
208 * each capability indiviually from the kernel */
209 if (result < 0) {
210 int cap = 0;
211 while (prctl(PR_CAPBSET_READ, cap) >= 0) cap++;
212 result = cap - 1;
213 }
214
215 return result;
216 }
217
218 int lxc_caps_last_cap(void)
219 {
220 static int last_cap = -1;
221 if (last_cap < 0) last_cap = _real_caps_last_cap();
222
223 return last_cap;
224 }
225
226 /*
227 * check if we have the caps needed to start a container. returns 1 on
228 * success, 0 on error. (I'd prefer this be a bool, but am afraid that
229 * might fail to build on some distros).
230 */
231 int lxc_caps_check(void)
232 {
233 uid_t uid = getuid();
234 cap_t caps;
235 cap_flag_value_t value;
236 int i, ret;
237
238 cap_value_t needed_caps[] = { CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_SETUID, CAP_SETGID };
239
240 #define NUMCAPS ((int) (sizeof(needed_caps) / sizeof(cap_t)))
241
242 if (!uid)
243 return 1;
244
245 caps = cap_get_proc();
246 if (!caps) {
247 ERROR("failed to cap_get_proc: %m");
248 return 0;
249 }
250
251 for (i=0; i<NUMCAPS; i++) {
252 ret = cap_get_flag(caps, needed_caps[i], CAP_EFFECTIVE, &value);
253 if (ret) {
254 ERROR("Failed to cap_get_flag: %m");
255 return 0;
256 }
257 if (!value) {
258 return 0;
259 }
260 }
261
262 return 1;
263 }
264 #endif