lxc_usernsexec.c revision 250b1eec71b074acdff1c5f6b5a1f0d7d2c20b77
/*
* (C) Copyright IBM Corp. 2008
* (C) Copyright Canonical, Inc 2010-2013
*
* Authors:
* Serge Hallyn <serge.hallyn@ubuntu.com>
* (Once upon a time, this was based on nsexec from the IBM
* container tools)
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <libgen.h>
#include <fcntl.h>
#include <sched.h>
#include <pwd.h>
#include <grp.h>
#include "namespace.h"
{
printf("usage: %s [-h] [-c] [-mnuUip] [-P <pid-file>]"
"[command [arg ..]]\n", name);
printf("\n");
printf(" -h this message\n");
printf("\n");
printf(" -m <uid-maps> uid maps to use\n");
printf("\n");
printf(" uid-maps: [u|g|b]:ns_id:host_id:range\n");
printf(" [u|g|b]: map user id, group id, or both\n");
printf(" ns_id: the base id in the new namespace\n");
printf(" host_id: the base id in the parent namespace\n");
printf(" range: how many ids to map\n");
printf(" Note: This program uses newuidmap(2) and newgidmap(2).\n");
printf(" calling user permission to use the mapped ranges\n");
exit(1);
}
if (fd == -1) {
sleep(1);
exit(1);
}
flags &= ~O_NONBLOCK;
for (i = 0; i < fd; i++)
close(i);
for (i = 0; i < 3; i++)
if (fd != i)
if (fd >= 3)
}
// Code copy end
{
// Assume we want to become root
if (setgid(0) < 0) {
perror("setgid");
return -1;
}
if (setuid(0) < 0) {
perror("setuid");
return -1;
}
perror("setgroups");
return -1;
}
if (unshare(CLONE_NEWNS) < 0) {
perror("unshare CLONE_NEWNS");
return -1;
}
perror("execvpe");
return -1;
}
struct id_map {
char which; // b or u or g
};
struct id_map default_map = {
.which = 'b',
.host_id = 100000,
.ns_id = 0,
.range = 10000,
};
/*
* given a string like "b:0:100000:10", map both uids and gids
* 0-10 to 100000 to 100010
*/
{
int ret;
if (!map)
return -1;
if (!newmap)
return -1;
ret = sscanf(map, "%c:%ld:%ld:%ld", &newmap->which, &newmap->ns_id, &newmap->host_id, &newmap->range);
if (ret != 4)
goto out_free_map;
goto out_free_map;
if (active_map != &default_map)
else
active_map = newmap;
return 0;
return -1;
}
/*
* allowed map. We only use the first one (bc otherwise we're
* not sure which ns ids he wants to use).
*/
{
if (!fin)
return -1;
continue;
if (!p1)
continue;
if (!p2)
continue;
if (!newmap)
return -1;
if (active_map != &default_map)
else
break;
}
if (line)
return 0;
}
#define subuidfile "/etc/subuid"
#define subgidfile "/etc/subgid"
static int find_default_map(void)
{
if (!p)
return -1;
return -1;
return -1;
return 0;
}
{
int status;
if (pid < 0)
return pid;
if (pid == 0) {
perror("exec failed");
exit(1);
}
perror("waitpid");
return -1;
}
return WEXITSTATUS(status);
}
{
struct id_map *m;
return -1;
return -1;
nuargs += 3;
if (!uidargs)
return -1;
return -1;
}
ngargs += 3;
if (!gidargs)
return -1;
return -1;
}
}
// exec newuidmap
return -2;
}
// exec newgidmap
return -2;
}
for (i=0; i<nuargs; i++)
for (i=0; i<ngargs; i++)
return 0;
}
{
int c;
char ttyname[256];
int status;
int ret;
int pid;
if (ret < 0) {
perror("readlink on fd 0");
exit(1);
}
switch (c) {
case 'h':
default:
}
};
if (active_map == &default_map) {
if (find_default_map()) {
exit(1);
}
}
if (argc < 1) {
argv = default_args;
argc = 1;
}
perror("pipe");
exit(1);
}
// Child.
if (ret < 0) {
perror("unshare");
return 1;
}
ret = 1;
perror("write pipe");
exit(1);
}
perror("read pipe");
exit(1);
}
if (ret != 1) {
exit(1);
}
}
perror("read pipe");
exit(1);
}
ret = 1;
ret = 0;
}
perror("write to pipe");
exit(1);
}
}
}