]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/cmd/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
30 #include <sys/syscall.h>
37 #include <sys/types.h>
38 #include <sys/mount.h>
45 #include "namespace.h"
53 #define MS_SLAVE (1 << 19)
56 extern int lxc_log_fd
;
58 int unshare(int flags
);
60 static void usage(const char *name
)
62 printf("usage: %s [-h] [-m <uid-maps>] -- [command [arg ..]]\n", name
);
64 printf(" -h this message\n");
66 printf(" -m <uid-maps> uid maps to use\n");
68 printf(" uid-maps: [u|g|b]:ns_id:host_id:range\n");
69 printf(" [u|g|b]: map user id, group id, or both\n");
70 printf(" ns_id: the base id in the new namespace\n");
71 printf(" host_id: the base id in the parent namespace\n");
72 printf(" range: how many ids to map\n");
73 printf(" Note: This program uses newuidmap(2) and newgidmap(2).\n");
74 printf(" As such, /etc/subuid and /etc/subgid must grant the\n");
75 printf(" calling user permission to use the mapped ranges\n");
78 static void opentty(const char *tty
, int which
)
85 fd
= open(tty
, O_RDWR
| O_NONBLOCK
);
87 printf("WARN: could not reopen tty: %s\n", strerror(errno
));
91 flags
= fcntl(fd
, F_GETFL
);
93 if (fcntl(fd
, F_SETFL
, flags
) < 0) {
94 printf("WARN: could not set fd flags: %s\n", strerror(errno
));
101 (void)dup2(fd
, which
);
107 static int do_child(void *vargv
)
109 char **argv
= (char **)vargv
;
111 /* Assume we want to become root */
120 if (setgroups(0, NULL
) < 0) {
124 if (unshare(CLONE_NEWNS
) < 0) {
125 perror("unshare CLONE_NEWNS");
128 if (detect_shared_rootfs()) {
129 if (mount(NULL
, "/", NULL
, MS_SLAVE
|MS_REC
, NULL
)) {
130 printf("Failed to make / rslave\n");
134 execvp(argv
[0], argv
);
139 static struct lxc_list active_map
;
142 * given a string like "b:0:100000:10", map both uids and gids
143 * 0-10 to 100000 to 100010
145 static int parse_map(char *map
)
147 struct id_map
*newmap
;
148 struct lxc_list
*tmp
= NULL
;
151 char types
[2] = {'u', 'g'};
153 long host_id
, ns_id
, range
;
158 ret
= sscanf(map
, "%c:%ld:%ld:%ld", &which
, &ns_id
, &host_id
, &range
);
162 if (which
!= 'b' && which
!= 'u' && which
!= 'g')
165 for (i
= 0; i
< 2; i
++) {
166 if (which
!= types
[i
] && which
!= 'b')
169 newmap
= malloc(sizeof(*newmap
));
173 newmap
->hostid
= host_id
;
174 newmap
->nsid
= ns_id
;
175 newmap
->range
= range
;
178 newmap
->idtype
= ID_TYPE_UID
;
180 newmap
->idtype
= ID_TYPE_GID
;
182 tmp
= malloc(sizeof(*tmp
));
189 lxc_list_add_tail(&active_map
, tmp
);
196 * This is called if the user did not pass any uid ranges in
197 * through -m flags. It's called once to get the default uid
198 * map, and once for the default gid map.
199 * Go through /etc/subuids and /etc/subgids to find this user's
200 * allowed map. We only use the first one for each of uid and
201 * gid, because otherwise we're not sure which entries the user
204 static int read_default_map(char *fnam
, int which
, char *username
)
209 struct id_map
*newmap
;
210 struct lxc_list
*tmp
= NULL
;
213 fin
= fopen(fnam
, "r");
216 while (getline(&line
, &sz
, fin
) != -1) {
217 if (sz
<= strlen(username
) ||
218 strncmp(line
, username
, strlen(username
)) != 0 ||
219 line
[strlen(username
)] != ':')
221 p1
= strchr(line
, ':');
224 p2
= strchr(p1
+1, ':');
227 newmap
= malloc(sizeof(*newmap
));
233 newmap
->hostid
= atol(p1
+1);
234 newmap
->range
= atol(p2
+1);
236 newmap
->idtype
= which
;
238 tmp
= malloc(sizeof(*tmp
));
247 lxc_list_add_tail(&active_map
, tmp
);
256 static int find_default_map(void)
259 struct passwd
*pwentp
= NULL
;
264 bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
);
268 buf
= malloc(bufsize
);
272 ret
= getpwuid_r(getuid(), &pwent
, buf
, bufsize
, &pwentp
);
275 printf("WARN: could not find matched password record\n");
277 printf("Failed to get password record - %u\n", getuid());
282 if (read_default_map(subuidfile
, ID_TYPE_UID
, pwent
.pw_name
) < 0) {
287 if (read_default_map(subgidfile
, ID_TYPE_GID
, pwent
.pw_name
) < 0) {
296 int main(int argc
, char *argv
[])
299 unsigned long flags
= CLONE_NEWUSER
| CLONE_NEWNS
;
300 char ttyname0
[256], ttyname1
[256], ttyname2
[256];
304 char *default_args
[] = {"/bin/sh", NULL
};
306 int pipe_fds1
[2], /* child tells parent it has unshared */
307 pipe_fds2
[2]; /* parent tells child it is mapped and may proceed */
309 lxc_log_fd
= STDERR_FILENO
;
311 memset(ttyname0
, '\0', sizeof(ttyname0
));
312 memset(ttyname1
, '\0', sizeof(ttyname1
));
313 memset(ttyname2
, '\0', sizeof(ttyname2
));
315 ret
= readlink("/proc/self/fd/0", ttyname0
, sizeof(ttyname0
));
317 perror("unable to open stdin.");
320 ret
= readlink("/proc/self/fd/1", ttyname1
, sizeof(ttyname1
));
322 printf("Warning: unable to open stdout, continuing.\n");
323 memset(ttyname1
, '\0', sizeof(ttyname1
));
325 ret
= readlink("/proc/self/fd/2", ttyname2
, sizeof(ttyname2
));
327 printf("Warning: unable to open stderr, continuing.\n");
328 memset(ttyname2
, '\0', sizeof(ttyname2
));
332 lxc_list_init(&active_map
);
334 while ((c
= getopt(argc
, argv
, "m:h")) != EOF
) {
337 if (parse_map(optarg
)) {
351 if (lxc_list_empty(&active_map
)) {
352 if (find_default_map()) {
353 fprintf(stderr
, "You have no allocated subuids or subgids\n");
358 argv
= &argv
[optind
];
359 argc
= argc
- optind
;
363 if (pipe2(pipe_fds1
, O_CLOEXEC
) < 0 || pipe2(pipe_fds2
, O_CLOEXEC
) < 0) {
368 if (pid
== 0) { /* Child. */
371 opentty(ttyname0
, 0);
372 opentty(ttyname1
, 1);
373 opentty(ttyname2
, 2);
375 ret
= unshare(flags
);
378 "Failed to unshare mount and user namespace\n");
382 if (lxc_write_nointr(pipe_fds1
[1], buf
, 1) < 1) {
383 perror("write pipe");
386 if (lxc_read_nointr(pipe_fds2
[0], buf
, 1) < 1) {
391 fprintf(stderr
, "parent had an error, child exiting\n");
397 return do_child((void *)argv
);
402 ret
= lxc_read_nointr(pipe_fds1
[0], buf
, 1);
406 } else if (ret
== 0) {
407 fprintf(stderr
, "Failed to read from pipe\n");
413 if (lxc_map_ids(&active_map
, pid
))
414 fprintf(stderr
, "error mapping child\n");
416 if (lxc_write_nointr(pipe_fds2
[1], buf
, 1) < 0) {
417 perror("write to pipe");
420 ret
= waitpid(pid
, &status
, __WALL
);
422 printf("waitpid() returns %d, errno %d\n", ret
, errno
);
426 exit(WEXITSTATUS(status
));