]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/caps.c
utils: Add lxc_append_paths to join two paths.
[mirror_lxc.git] / src / lxc / caps.c
CommitLineData
b3357a6f
DL
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
b3357a6f
DL
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
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
b3357a6f
DL
22 */
23
24#define _GNU_SOURCE
25#include <unistd.h>
20d81659
CS
26#include <fcntl.h>
27#include <stdlib.h>
28#include <limits.h>
b3357a6f 29#include <sys/prctl.h>
2b657f10 30#include <errno.h>
b3357a6f 31
495d2046 32#include "config.h"
b3357a6f
DL
33#include "log.h"
34
35lxc_log_define(lxc_caps, lxc);
36
495d2046
SG
37#if HAVE_SYS_CAPABILITY_H
38#include <sys/capability.h>
39
cbec0030
SG
40#ifndef PR_CAPBSET_READ
41#define PR_CAPBSET_READ 23
42#endif
43
05cda563
DL
44int lxc_caps_reset(void)
45{
46 cap_t cap = cap_init();
47 int ret = 0;
48
49 if (!cap) {
50 ERROR("cap_init() failed : %m");
51 return -1;
52 }
53
54 if (cap_set_proc(cap)) {
55 ERROR("cap_set_proc() failed : %m");
56 ret = -1;
57 }
58
59 cap_free(cap);
60 return ret;
61}
62
b3357a6f
DL
63int lxc_caps_down(void)
64{
65 cap_t caps;
66 int ret;
67
7ee895e4
DL
68 /* when we are run as root, we don't want to play
69 * with the capabilities */
70 if (!getuid())
71 return 0;
72
b3357a6f
DL
73 caps = cap_get_proc();
74 if (!caps) {
75 ERROR("failed to cap_get_proc: %m");
76 return -1;
77 }
78
79 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
80 if (ret) {
81 ERROR("failed to cap_clear_flag: %m");
82 goto out;
83 }
84
85 ret = cap_set_proc(caps);
86 if (ret) {
87 ERROR("failed to cap_set_proc: %m");
88 goto out;
89 }
90
91out:
92 cap_free(caps);
93 return 0;
94}
95
96int lxc_caps_up(void)
97{
98 cap_t caps;
99 cap_value_t cap;
100 int ret;
101
7ee895e4
DL
102 /* when we are run as root, we don't want to play
103 * with the capabilities */
104 if (!getuid())
105 return 0;
106
b3357a6f
DL
107 caps = cap_get_proc();
108 if (!caps) {
109 ERROR("failed to cap_get_proc: %m");
110 return -1;
111 }
112
113 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
114
115 cap_flag_value_t flag;
116
117 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
118 if (ret) {
2b657f10
SH
119 if (errno == EINVAL) {
120 INFO("Last supported cap was %d\n", cap-1);
121 break;
122 } else {
123 ERROR("failed to cap_get_flag: %m");
124 goto out;
125 }
b3357a6f
DL
126 }
127
128 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
129 if (ret) {
130 ERROR("failed to cap_set_flag: %m");
131 goto out;
132 }
133 }
134
135 ret = cap_set_proc(caps);
136 if (ret) {
137 ERROR("failed to cap_set_proc: %m");
138 goto out;
139 }
140
141out:
142 cap_free(caps);
143 return 0;
144}
145
146int lxc_caps_init(void)
147{
148 uid_t uid = getuid();
149 gid_t gid = getgid();
150 uid_t euid = geteuid();
151
152 if (!uid) {
153 INFO("command is run as 'root'");
154 return 0;
155 }
156
157 if (uid && !euid) {
158 INFO("command is run as setuid root (uid : %d)", uid);
159
160 if (prctl(PR_SET_KEEPCAPS, 1)) {
161 ERROR("failed to 'PR_SET_KEEPCAPS': %m");
162 return -1;
163 }
164
165 if (setresgid(gid, gid, gid)) {
166 ERROR("failed to change gid to '%d': %m", gid);
167 return -1;
168 }
169
170 if (setresuid(uid, uid, uid)) {
171 ERROR("failed to change uid to '%d': %m", uid);
172 return -1;
173 }
174
175 if (lxc_caps_up()) {
176 ERROR("failed to restore capabilities: %m");
177 return -1;
178 }
179 }
180
181 if (uid == euid)
182 INFO("command is run as user '%d'", uid);
183
184 return 0;
185}
20d81659
CS
186
187static int _real_caps_last_cap(void)
188{
189 int fd;
190 int result = -1;
191
192 /* try to get the maximum capability over the kernel
193 * interface introduced in v3.2 */
194 fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY);
195 if (fd >= 0) {
196 char buf[32];
197 char *ptr;
198 int n;
199
200 if ((n = read(fd, buf, 31)) >= 0) {
201 buf[n] = '\0';
202 result = strtol(buf, &ptr, 10);
203 if (!ptr || (*ptr != '\0' && *ptr != '\n') ||
204 result == LONG_MIN || result == LONG_MAX)
205 result = -1;
206 }
207
208 close(fd);
209 }
210
211 /* try to get it manually by trying to get the status of
212 * each capability indiviually from the kernel */
213 if (result < 0) {
214 int cap = 0;
215 while (prctl(PR_CAPBSET_READ, cap) >= 0) cap++;
216 result = cap - 1;
217 }
218
219 return result;
220}
221
222int lxc_caps_last_cap(void)
223{
224 static int last_cap = -1;
225 if (last_cap < 0) last_cap = _real_caps_last_cap();
226
227 return last_cap;
228}
4a2ca8b2 229
495d2046 230#endif