~ubuntu-branches/ubuntu/quantal/lxc/quantal-201208301614

« back to all changes in this revision

Viewing changes to .pc/0104-add-option-to-lxc-attach-to-select-ns/src/lxc/lxc_unshare.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2012-08-21 16:10:08 UTC
  • Revision ID: package-import@ubuntu.com-20120821161008-0fhg53kqdfn9u3aj
Tags: 0.8.0~rc1-4ubuntu27
* Add patches from mailing list to support per-namespace attach with
  lxc-attach.
  - 0104-add-option-to-lxc-attach-to-select-ns
  - 0105-lxc-attach-add-R-option

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * lxc: linux Container library
 
3
 *
 
4
 * (C) Copyright IBM Corp. 2007, 2008
 
5
 *
 
6
 * Authors:
 
7
 * Daniel Lezcano <dlezcano at fr.ibm.com>
 
8
 *
 
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.
 
13
 *
 
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.
 
18
 *
 
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
 
22
 */
 
23
#define _GNU_SOURCE
 
24
#include <stdio.h>
 
25
#undef _GNU_SOURCE
 
26
#include <stdlib.h>
 
27
#include <unistd.h>
 
28
#include <libgen.h>
 
29
#include <getopt.h>
 
30
#include <string.h>
 
31
#include <signal.h>
 
32
#include <errno.h>
 
33
#include <sys/types.h>
 
34
#include <sys/wait.h>
 
35
#include <pwd.h>
 
36
 
 
37
#include "caps.h"
 
38
#include "log.h"
 
39
#include "namespace.h"
 
40
#include "cgroup.h"
 
41
#include "error.h"
 
42
 
 
43
lxc_log_define(lxc_unshare_ui, lxc);
 
44
 
 
45
void usage(char *cmd)
 
46
{
 
47
        fprintf(stderr, "%s <options> command [command_arguments]\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
        _exit(1);
 
53
}
 
54
 
 
55
static uid_t lookup_user(const char *optarg)
 
56
{
 
57
        int bufflen = sysconf(_SC_GETPW_R_SIZE_MAX);
 
58
        char buff[bufflen];
 
59
        char name[sysconf(_SC_LOGIN_NAME_MAX)];
 
60
        uid_t uid = -1;
 
61
        struct passwd pwent;
 
62
        struct passwd *pent;
 
63
 
 
64
        if (!optarg || (optarg[0] == '\0'))
 
65
                return uid;
 
66
 
 
67
        if (sscanf(optarg, "%u", &uid) < 1) {
 
68
                /* not a uid -- perhaps a username */
 
69
                if (sscanf(optarg, "%s", name) < 1)
 
70
                        return uid;
 
71
 
 
72
                if (getpwnam_r(name, &pwent, buff, bufflen, &pent) || !pent) {
 
73
                        ERROR("invalid username %s", name);
 
74
                        return uid;
 
75
                }
 
76
                uid = pent->pw_uid;
 
77
        } else {
 
78
                if (getpwuid_r(uid, &pwent, buff, bufflen, &pent) || !pent) {
 
79
                        ERROR("invalid uid %d", uid);
 
80
                        uid = -1;
 
81
                        return uid;
 
82
                }
 
83
        }
 
84
        return uid;
 
85
}
 
86
 
 
87
static char *namespaces_list[] = {
 
88
        "MOUNT", "PID", "UTSNAME", "IPC",
 
89
        "USER", "NETWORK"
 
90
};
 
91
static int cloneflags_list[] = {
 
92
        CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
 
93
        CLONE_NEWUSER, CLONE_NEWNET
 
94
};
 
95
 
 
96
static int lxc_namespace_2_cloneflag(char *namespace)
 
97
{
 
98
        int i, len;
 
99
        len = sizeof(namespaces_list)/sizeof(namespaces_list[0]);
 
100
        for (i = 0; i < len; i++)
 
101
                if (!strcmp(namespaces_list[i], namespace))
 
102
                        return cloneflags_list[i];
 
103
 
 
104
        ERROR("invalid namespace name %s", namespace);
 
105
        return -1;
 
106
}
 
107
 
 
108
static int lxc_fill_namespace_flags(char *flaglist, int *flags)
 
109
{
 
110
        char *token, *saveptr = NULL;
 
111
        int aflag;
 
112
 
 
113
        if (!flaglist) {
 
114
                ERROR("need at least one namespace to unshare");
 
115
                return -1;
 
116
        }
 
117
 
 
118
        token = strtok_r(flaglist, "|", &saveptr);
 
119
        while (token) {
 
120
 
 
121
                aflag = lxc_namespace_2_cloneflag(token);
 
122
                if (aflag < 0)
 
123
                        return -1;
 
124
 
 
125
                *flags |= aflag;
 
126
 
 
127
                token = strtok_r(NULL, "|", &saveptr);
 
128
        }
 
129
        return 0;
 
130
}
 
131
 
 
132
 
 
133
struct start_arg {
 
134
        char ***args;
 
135
        int *flags;
 
136
        uid_t *uid;
 
137
};
 
138
 
 
139
static int do_start(void *arg)
 
140
{
 
141
        struct start_arg *start_arg = arg;
 
142
        char **args = *start_arg->args;
 
143
        int flags = *start_arg->flags;
 
144
        uid_t uid = *start_arg->uid;
 
145
 
 
146
        if (flags & CLONE_NEWUSER && setuid(uid)) {
 
147
                ERROR("failed to set uid %d: %s", uid, strerror(errno));
 
148
                exit(1);
 
149
        }
 
150
 
 
151
        execvp(args[0], args);
 
152
 
 
153
        ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
 
154
        return 1;
 
155
}
 
156
 
 
157
int main(int argc, char *argv[])
 
158
{
 
159
        int opt, status;
 
160
        int ret;
 
161
        char *pid_name;
 
162
        char *namespaces = NULL;
 
163
        char **args;
 
164
        int flags = 0;
 
165
        uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */
 
166
        pid_t pid;
 
167
 
 
168
        struct start_arg start_arg = {
 
169
                .args = &args,
 
170
                .uid = &uid,
 
171
                .flags = &flags,
 
172
        };
 
173
 
 
174
        while ((opt = getopt(argc, argv, "s:u:")) != -1) {
 
175
                switch (opt) {
 
176
                case 's':
 
177
                        namespaces = optarg;
 
178
                        break;
 
179
                case 'u':
 
180
                        uid = lookup_user(optarg);
 
181
                        if (uid == -1)
 
182
                                return 1;
 
183
                }
 
184
        }
 
185
 
 
186
    if (argv[optind] == NULL) {
 
187
        ERROR("a command to execute in the new namespace is required");
 
188
        return 1;
 
189
    }
 
190
 
 
191
        args = &argv[optind];
 
192
 
 
193
        ret = lxc_caps_init();
 
194
        if (ret)
 
195
                return ret;
 
196
 
 
197
        ret = lxc_fill_namespace_flags(namespaces, &flags);
 
198
        if (ret)
 
199
                usage(argv[0]);
 
200
 
 
201
        if (!(flags & CLONE_NEWUSER) && uid != -1) {
 
202
                ERROR("-u <uid> needs -s USER option");
 
203
                return 1;
 
204
        }
 
205
 
 
206
        pid = lxc_clone(do_start, &start_arg, flags);
 
207
        if (pid < 0) {
 
208
                ERROR("failed to clone");
 
209
                return -1;
 
210
        }
 
211
 
 
212
        if (waitpid(pid, &status, 0) < 0) {
 
213
                ERROR("failed to wait for '%d'", pid);
 
214
                return -1;
 
215
        }
 
216
 
 
217
        if (lxc_ns_is_mounted()) {
 
218
                if (asprintf(&pid_name, "%d", pid) == -1) {
 
219
                        ERROR("pid_name: failed to allocate memory");
 
220
                        return -1;
 
221
                }
 
222
                lxc_cgroup_destroy(pid_name);
 
223
                free(pid_name);
 
224
        }
 
225
 
 
226
        return  lxc_error_set_and_log(pid, status);
 
227
}