2
* lxc: linux Container library
4
* (C) Copyright IBM Corp. 2007, 2008
7
* Daniel Lezcano <dlezcano at fr.ibm.com>
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.
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.
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
21
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33
#include <sys/types.h>
39
#include "namespace.h"
43
lxc_log_define(lxc_unshare_ui, lxc);
47
fprintf(stderr, "%s <options> [command]\n", basename(cmd));
48
fprintf(stderr, "Options are:\n");
49
fprintf(stderr, "\t -s flags: ORed list of flags to unshare:\n" \
50
"\t MOUNT, PID, UTSNAME, IPC, USER, NETWORK\n");
51
fprintf(stderr, "\t -u <id> : new id to be set if -s USER is specified\n");
52
fprintf(stderr, "\t if -s PID is specified, <command> is mandatory)\n");
56
static uid_t lookup_user(const char *optarg)
58
int bufflen = sysconf(_SC_GETPW_R_SIZE_MAX);
60
char name[sysconf(_SC_LOGIN_NAME_MAX)];
65
if (!optarg || (optarg[0] == '\0'))
68
if (sscanf(optarg, "%u", &uid) < 1) {
69
/* not a uid -- perhaps a username */
70
if (sscanf(optarg, "%s", name) < 1)
73
if (getpwnam_r(name, &pwent, buff, bufflen, &pent) || !pent) {
74
ERROR("invalid username %s", name);
79
if (getpwuid_r(uid, &pwent, buff, bufflen, &pent) || !pent) {
80
ERROR("invalid uid %d", uid);
88
static char *namespaces_list[] = {
89
"MOUNT", "PID", "UTSNAME", "IPC",
92
static int cloneflags_list[] = {
93
CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
94
CLONE_NEWUSER, CLONE_NEWNET
97
static int lxc_namespace_2_cloneflag(char *namespace)
100
len = sizeof(namespaces_list)/sizeof(namespaces_list[0]);
101
for (i = 0; i < len; i++)
102
if (!strcmp(namespaces_list[i], namespace))
103
return cloneflags_list[i];
105
ERROR("invalid namespace name %s", namespace);
109
static int lxc_fill_namespace_flags(char *flaglist, int *flags)
111
char *token, *saveptr = NULL;
115
ERROR("need at least one namespace to unshare");
119
token = strtok_r(flaglist, "|", &saveptr);
122
aflag = lxc_namespace_2_cloneflag(token);
128
token = strtok_r(NULL, "|", &saveptr);
140
static int do_start(void *arg)
142
struct start_arg *start_arg = arg;
143
char **args = *start_arg->args;
144
int flags = *start_arg->flags;
145
uid_t uid = *start_arg->uid;
147
if (flags & CLONE_NEWUSER && setuid(uid)) {
148
ERROR("failed to set uid %d: %s", uid, strerror(errno));
152
execvp(args[0], args);
154
ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
158
int main(int argc, char *argv[])
163
char *namespaces = NULL;
166
uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */
169
struct start_arg start_arg = {
175
while ((opt = getopt(argc, argv, "s:u:")) != -1) {
181
uid = lookup_user(optarg);
187
args = &argv[optind];
189
ret = lxc_caps_init();
193
ret = lxc_fill_namespace_flags(namespaces, &flags);
197
if (!(flags & CLONE_NEWUSER) && uid != -1) {
198
ERROR("-u <uid> needs -s USER option");
202
pid = lxc_clone(do_start, &start_arg, flags);
204
ERROR("failed to clone");
208
if (waitpid(pid, &status, 0) < 0) {
209
ERROR("failed to wait for '%d'", pid);
213
if (lxc_ns_is_mounted()) {
214
if (asprintf(&pid_name, "%d", pid) == -1) {
215
ERROR("pid_name: failed to allocate memory");
218
lxc_cgroup_destroy(pid_name);
222
return lxc_error_set_and_log(pid, status);