]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/cmd/lxc_usernsexec.c
10557dd5192fb7fd0ac1f48784ac1d92789ce6e2
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
38 #include <sys/mount.h>
40 #include <sys/syscall.h>
41 #include <sys/types.h>
50 #include "file_utils.h"
51 #include "string_utils.h"
52 #include "syscall_wrappers.h"
55 extern int lxc_log_fd
;
57 static void usage(const char *name
)
59 printf("usage: %s [-h] [-m <uid-maps>] -- [command [arg ..]]\n", name
);
61 printf(" -h this message\n");
63 printf(" -m <uid-maps> uid maps to use\n");
65 printf(" uid-maps: [u|g|b]:ns_id:host_id:range\n");
66 printf(" [u|g|b]: map user id, group id, or both\n");
67 printf(" ns_id: the base id in the new namespace\n");
68 printf(" host_id: the base id in the parent namespace\n");
69 printf(" range: how many ids to map\n");
70 printf(" Note: This program uses newuidmap(2) and newgidmap(2).\n");
71 printf(" As such, /etc/subuid and /etc/subgid must grant the\n");
72 printf(" calling user permission to use the mapped ranges\n");
75 static void opentty(const char *tty
, int which
)
82 fd
= open(tty
, O_RDWR
| O_NONBLOCK
);
84 CMD_SYSERROR("Failed to open tty");
88 flags
= fcntl(fd
, F_GETFL
);
90 ret
= fcntl(fd
, F_SETFL
, flags
);
92 CMD_SYSINFO("Failed to remove O_NONBLOCK from file descriptor %d", fd
);
99 (void)dup2(fd
, which
);
105 static int do_child(void *vargv
)
108 char **argv
= (char **)vargv
;
110 /* Assume we want to become root */
111 if (!lxc_switch_uid_gid(0, 0))
114 if (!lxc_setgroups(0, NULL
))
117 ret
= unshare(CLONE_NEWNS
);
119 CMD_SYSERROR("Failed to unshare mount namespace");
123 if (detect_shared_rootfs()) {
124 ret
= mount(NULL
, "/", NULL
, MS_SLAVE
| MS_REC
, NULL
);
126 CMD_SYSINFO("Failed to make \"/\" rslave");
131 execvp(argv
[0], argv
);
132 CMD_SYSERROR("Failed to execute \"%s\"", argv
[0]);
136 static struct lxc_list active_map
;
139 * Given a string like "b:0:100000:10", map both uids and gids 0-10 to 100000
142 static int parse_map(char *map
)
145 long host_id
, ns_id
, range
;
147 struct id_map
*newmap
;
148 char types
[2] = {'u', 'g'};
149 struct lxc_list
*tmp
= NULL
;
154 ret
= sscanf(map
, "%c:%ld:%ld:%ld", &which
, &ns_id
, &host_id
, &range
);
158 if (which
!= 'b' && which
!= 'u' && which
!= 'g')
161 for (i
= 0; i
< 2; i
++) {
162 if (which
!= types
[i
] && which
!= 'b')
165 newmap
= malloc(sizeof(*newmap
));
169 newmap
->hostid
= host_id
;
170 newmap
->nsid
= ns_id
;
171 newmap
->range
= range
;
174 newmap
->idtype
= ID_TYPE_UID
;
176 newmap
->idtype
= ID_TYPE_GID
;
178 tmp
= malloc(sizeof(*tmp
));
185 lxc_list_add_tail(&active_map
, tmp
);
192 * This is called if the user did not pass any uid ranges in through -m flags.
193 * It's called once to get the default uid map, and once for the default gid
195 * Go through /etc/subuids and /etc/subgids to find this user's allowed map. We
196 * only use the first one for each of uid and gid, because otherwise we're not
197 * sure which entries the user wanted.
199 static int read_default_map(char *fnam
, int which
, char *user
)
207 struct lxc_list
*tmp
= NULL
;
208 struct id_map
*newmap
= NULL
;
210 fin
= fopen(fnam
, "r");
215 while (getline(&line
, &sz
, fin
) != -1) {
216 if (sz
<= len
|| strncmp(line
, user
, len
) != 0 || line
[len
] != ':')
219 p1
= strchr(line
, ':');
223 p2
= strchr(p1
+ 1, ':');
227 newmap
= malloc(sizeof(*newmap
));
231 ret
= lxc_safe_ulong(p1
+ 1, &newmap
->hostid
);
235 ret
= lxc_safe_ulong(p2
+ 1, &newmap
->range
);
240 newmap
->idtype
= which
;
243 tmp
= malloc(sizeof(*tmp
));
248 lxc_list_add_tail(&active_map
, tmp
);
262 static int find_default_map(void)
268 struct passwd
*pwentp
= NULL
;
270 bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
);
274 buf
= malloc(bufsize
);
278 ret
= getpwuid_r(getuid(), &pwent
, buf
, bufsize
, &pwentp
);
281 CMD_SYSERROR("Failed to find matched password record");
283 CMD_SYSERROR("Failed to get password record for uid %d", getuid());
288 ret
= read_default_map(subuidfile
, ID_TYPE_UID
, pwent
.pw_name
);
292 ret
= read_default_map(subgidfile
, ID_TYPE_GID
, pwent
.pw_name
);
304 int main(int argc
, char *argv
[])
306 int c
, pid
, ret
, status
;
308 int pipe_fds1
[2], /* child tells parent it has unshared */
309 pipe_fds2
[2]; /* parent tells child it is mapped and may proceed */
310 unsigned long flags
= CLONE_NEWUSER
| CLONE_NEWNS
;
311 char ttyname0
[256] = {0}, ttyname1
[256] = {0}, ttyname2
[256] = {0};
312 char *default_args
[] = {"/bin/sh", NULL
};
314 lxc_log_fd
= STDERR_FILENO
;
316 if (isatty(STDIN_FILENO
)) {
317 ret
= readlink("/proc/self/fd/0", ttyname0
, sizeof(ttyname0
));
319 CMD_SYSERROR("Failed to open stdin");
323 ret
= readlink("/proc/self/fd/1", ttyname1
, sizeof(ttyname1
));
325 CMD_SYSINFO("Failed to open stdout. Continuing");
329 ret
= readlink("/proc/self/fd/2", ttyname2
, sizeof(ttyname2
));
331 CMD_SYSINFO("Failed to open stderr. Continuing");
336 lxc_list_init(&active_map
);
338 while ((c
= getopt(argc
, argv
, "m:h")) != EOF
) {
341 ret
= parse_map(optarg
);
356 if (lxc_list_empty(&active_map
)) {
357 ret
= find_default_map();
359 fprintf(stderr
, "Failed to find subuid or subgid allocation\n");
364 argv
= &argv
[optind
];
365 argc
= argc
- optind
;
369 ret
= pipe2(pipe_fds1
, O_CLOEXEC
);
371 CMD_SYSERROR("Failed to open new pipe");
375 ret
= pipe2(pipe_fds2
, O_CLOEXEC
);
377 CMD_SYSERROR("Failed to open new pipe");
396 opentty(ttyname0
, STDIN_FILENO
);
397 opentty(ttyname1
, STDOUT_FILENO
);
398 opentty(ttyname2
, STDERR_FILENO
);
400 ret
= unshare(flags
);
402 CMD_SYSERROR("Failed to unshare mount and user namespace");
409 ret
= lxc_write_nointr(pipe_fds1
[1], buf
, 1);
411 CMD_SYSERROR("Failed to write to pipe file descriptor %d",
418 ret
= lxc_read_nointr(pipe_fds2
[0], buf
, 1);
420 CMD_SYSERROR("Failed to read from pipe file descriptor %d",
431 fprintf(stderr
, "Received unexpected value from parent process\n");
435 ret
= do_child((void *)argv
);
445 ret
= lxc_read_nointr(pipe_fds1
[0], buf
, 1);
447 CMD_SYSERROR("Failed to read from pipe file descriptor %d", pipe_fds1
[0]);
451 ret
= lxc_map_ids(&active_map
, pid
);
453 fprintf(stderr
, "Failed to write id mapping for child process\n");
455 ret
= lxc_write_nointr(pipe_fds2
[1], buf
, 1);
457 CMD_SYSERROR("Failed to write to pipe file descriptor %d", pipe_fds2
[1]);
461 ret
= waitpid(pid
, &status
, __WALL
);
463 CMD_SYSERROR("Failed to wait on child process");
467 _exit(WEXITSTATUS(status
));