]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_usernsexec.c
2 * (C) Copyright IBM Corp. 2008
3 * (C) Copyright Canonical, Inc 2010-2013
6 * Serge Hallyn <serge.hallyn@ubuntu.com>
7 * (Once upon a time, this was based on nsexec from the IBM
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <sys/syscall.h>
36 #include <sys/types.h>
41 #include "namespace.h"
43 int unshare(int flags
);
45 static void usage(const char *name
)
47 printf("usage: %s [-h] [-c] [-mnuUip] [-P <pid-file>]"
48 "[command [arg ..]]\n", name
);
50 printf(" -h this message\n");
52 printf(" -m <uid-maps> uid maps to use\n");
54 printf(" uid-maps: [u|g|b]:ns_id:host_id:range\n");
55 printf(" [u|g|b]: map user id, group id, or both\n");
56 printf(" ns_id: the base id in the new namespace\n");
57 printf(" host_id: the base id in the parent namespace\n");
58 printf(" range: how many ids to map\n");
59 printf(" Note: This program uses newuidmap(2) and newgidmap(2).\n");
60 printf(" As such, /etc/subuid and /etc/subgid must grant the\n");
61 printf(" calling user permission to use the mapped ranges\n");
65 static void opentty(const char * tty
) {
68 fd
= open(tty
, O_RDWR
| O_NONBLOCK
);
70 printf("FATAL: can't reopen tty: %s", strerror(errno
));
75 flags
= fcntl(fd
, F_GETFL
);
77 fcntl(fd
, F_SETFL
, flags
);
79 for (i
= 0; i
< fd
; i
++)
81 for (i
= 0; i
< 3; i
++)
89 static int do_child(void *vargv
)
91 char **argv
= (char **)vargv
;
93 // Assume we want to become root
102 if (setgroups(0, NULL
) < 0) {
106 if (unshare(CLONE_NEWNS
) < 0) {
107 perror("unshare CLONE_NEWNS");
110 execvp(argv
[0], argv
);
116 char which
; // b or u or g
117 long host_id
, ns_id
, range
;
121 struct id_map default_map
= {
127 static struct id_map
*active_map
= &default_map
;
130 * given a string like "b:0:100000:10", map both uids and gids
131 * 0-10 to 100000 to 100010
133 static int parse_map(char *map
)
135 struct id_map
*newmap
;
140 newmap
= malloc(sizeof(*newmap
));
143 ret
= sscanf(map
, "%c:%ld:%ld:%ld", &newmap
->which
, &newmap
->ns_id
, &newmap
->host_id
, &newmap
->range
);
146 if (newmap
->which
!= 'b' && newmap
->which
!= 'u' && newmap
->which
!= 'g')
148 if (active_map
!= &default_map
)
149 newmap
->next
= active_map
;
161 * go through /etc/subuids and /etc/subgids to find this user's
162 * allowed map. We only use the first one (bc otherwise we're
163 * not sure which ns ids he wants to use).
165 static int read_default_map(char *fnam
, char which
, char *username
)
170 struct id_map
*newmap
;
173 fin
= fopen(fnam
, "r");
176 while (getline(&line
, &sz
, fin
) != -1) {
177 if (sz
<= strlen(username
) ||
178 strncmp(line
, username
, strlen(username
)) != 0 ||
179 line
[strlen(username
)] != ':')
181 p1
= index(line
, ':');
184 p2
= index(p1
+1, ':');
187 newmap
= malloc(sizeof(*newmap
));
190 newmap
->host_id
= atol(p1
+1);
191 newmap
->range
= atol(p2
+1);
193 newmap
->which
= which
;
194 if (active_map
!= &default_map
)
195 newmap
->next
= active_map
;
207 #define subuidfile "/etc/subuid"
208 #define subgidfile "/etc/subgid"
209 static int find_default_map(void)
211 struct passwd
*p
= getpwuid(getuid());
214 if (read_default_map(subuidfile
, 'u', p
->pw_name
) < 0)
216 if (read_default_map(subgidfile
, 'g', p
->pw_name
) < 0)
221 static int run_cmd(char **argv
)
229 execvp(argv
[0], argv
);
230 perror("exec failed");
233 if (waitpid(pid
, &status
, __WALL
) < 0) {
238 return WEXITSTATUS(status
);
241 static int map_child_uids(int pid
, struct id_map
*map
)
243 char **uidargs
= NULL
, **gidargs
= NULL
;
244 int i
, nuargs
= 2, ngargs
= 2;
247 uidargs
= malloc(3 * sizeof(*uidargs
));
248 gidargs
= malloc(3 * sizeof(*gidargs
));
249 if (uidargs
== NULL
|| gidargs
== NULL
)
251 uidargs
[0] = malloc(10);
252 gidargs
[0] = malloc(10);
253 uidargs
[1] = malloc(21);
254 gidargs
[1] = malloc(21);
257 if (!uidargs
[0] || !uidargs
[1] || !gidargs
[0] || !gidargs
[1])
259 sprintf(uidargs
[0], "newuidmap");
260 sprintf(gidargs
[0], "newgidmap");
261 sprintf(uidargs
[1], "%d", pid
);
262 sprintf(gidargs
[1], "%d", pid
);
263 for (m
=map
; m
; m
= m
->next
) {
264 if (m
->which
== 'b' || m
->which
== 'u') {
266 uidargs
= realloc(uidargs
, (nuargs
+1) * sizeof(*uidargs
));
269 uidargs
[nuargs
- 3] = malloc(21);
270 uidargs
[nuargs
- 2] = malloc(21);
271 uidargs
[nuargs
- 1] = malloc(21);
272 if (!uidargs
[nuargs
-3] || !uidargs
[nuargs
-2] || !uidargs
[nuargs
-1])
274 sprintf(uidargs
[nuargs
- 3], "%ld", m
->ns_id
);
275 sprintf(uidargs
[nuargs
- 2], "%ld", m
->host_id
);
276 sprintf(uidargs
[nuargs
- 1], "%ld", m
->range
);
277 uidargs
[nuargs
] = NULL
;
279 if (m
->which
== 'b' || m
->which
== 'g') {
281 gidargs
= realloc(gidargs
, (ngargs
+1) * sizeof(*gidargs
));
284 gidargs
[ngargs
- 3] = malloc(21);
285 gidargs
[ngargs
- 2] = malloc(21);
286 gidargs
[ngargs
- 1] = malloc(21);
287 if (!gidargs
[ngargs
-3] || !gidargs
[ngargs
-2] || !gidargs
[ngargs
-1])
289 sprintf(gidargs
[ngargs
- 3], "%ld", m
->ns_id
);
290 sprintf(gidargs
[ngargs
- 2], "%ld", m
->host_id
);
291 sprintf(gidargs
[ngargs
- 1], "%ld", m
->range
);
292 gidargs
[ngargs
] = NULL
;
297 if (nuargs
> 2 && run_cmd(uidargs
) != 0) {
298 fprintf(stderr
, "Error mapping uids\n");
302 if (ngargs
> 2 && run_cmd(gidargs
) != 0) {
303 fprintf(stderr
, "Error mapping gids\n");
307 for (i
=0; i
<nuargs
; i
++)
309 for (i
=0; i
<ngargs
; i
++)
317 int main(int argc
, char *argv
[])
320 unsigned long flags
= CLONE_NEWUSER
| CLONE_NEWNS
;
325 char *default_args
[] = {"/bin/sh", NULL
};
326 int pipe1
[2], // child tells parent it has unshared
327 pipe2
[2]; // parent tells child it is mapped and may proceed
329 memset(ttyname
, '\0', sizeof(ttyname
));
330 ret
= readlink("/proc/self/fd/0", ttyname
, sizeof(ttyname
));
332 perror("readlink on fd 0");
336 while ((c
= getopt(argc
, argv
, "m:h")) != EOF
) {
338 case 'm': if (parse_map(optarg
)) usage(argv
[0]); break;
345 if (active_map
== &default_map
) {
346 if (find_default_map()) {
347 fprintf(stderr
, "You have no allocated subuids or subgids\n");
352 argv
= &argv
[optind
];
353 argc
= argc
- optind
;
359 if (pipe(pipe1
) < 0 || pipe(pipe2
) < 0) {
363 if ((pid
= fork()) == 0) {
370 ret
= unshare(flags
);
376 if (write(pipe1
[1], &ret
, 1) < 1) {
377 perror("write pipe");
380 if (read(pipe2
[0], &ret
, 1) < 1) {
385 fprintf(stderr
, "parent had an error, child exiting\n");
391 return do_child((void*)argv
);
396 if (read(pipe1
[0], &ret
, 1) < 1) {
402 if (map_child_uids(pid
, active_map
)) {
403 fprintf(stderr
, "error mapping child\n");
406 if (write(pipe2
[1], &ret
, 1) < 0) {
407 perror("write to pipe");
411 if ((ret
= waitpid(pid
, &status
, __WALL
)) < 0) {
412 printf("waitpid() returns %d, errno %d\n", ret
, errno
);
416 exit(WEXITSTATUS(status
));