~ubuntu-branches/ubuntu/quantal/lxc/quantal-201208081743

« back to all changes in this revision

Viewing changes to .pc/0086-lxc-unshare-zero-args/src/lxc/lxc_unshare.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2012-06-11 15:46:25 UTC
  • Revision ID: package-import@ubuntu.com-20120611154625-s5yxhd86bti3klv8
Tags: 0.8.0~rc1-4ubuntu13
* 0086-lxc-unshare-zero-args: fix lxc-unshare segfaulting when no command
  is given (LP: #1011603)
* 0087-lxc-ls-dash: fix lxc-ls for containers whose names start with a
  dash  (LP: #1006332)
* 0088-ubuntu-template-flock: don't fail when flock is busy, just wait,
  so concurrent lxc-creates don't break.  (LP: #1007483)
* 0089-lxc-netstat-exec: fix lxc-netstat errors (LP: #1011739)

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]\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");
 
53
        _exit(1);
 
54
}
 
55
 
 
56
static uid_t lookup_user(const char *optarg)
 
57
{
 
58
        int bufflen = sysconf(_SC_GETPW_R_SIZE_MAX);
 
59
        char buff[bufflen];
 
60
        char name[sysconf(_SC_LOGIN_NAME_MAX)];
 
61
        uid_t uid = -1;
 
62
        struct passwd pwent;
 
63
        struct passwd *pent;
 
64
 
 
65
        if (!optarg || (optarg[0] == '\0'))
 
66
                return uid;
 
67
 
 
68
        if (sscanf(optarg, "%u", &uid) < 1) {
 
69
                /* not a uid -- perhaps a username */
 
70
                if (sscanf(optarg, "%s", name) < 1)
 
71
                        return uid;
 
72
 
 
73
                if (getpwnam_r(name, &pwent, buff, bufflen, &pent) || !pent) {
 
74
                        ERROR("invalid username %s", name);
 
75
                        return uid;
 
76
                }
 
77
                uid = pent->pw_uid;
 
78
        } else {
 
79
                if (getpwuid_r(uid, &pwent, buff, bufflen, &pent) || !pent) {
 
80
                        ERROR("invalid uid %d", uid);
 
81
                        uid = -1;
 
82
                        return uid;
 
83
                }
 
84
        }
 
85
        return uid;
 
86
}
 
87
 
 
88
static char *namespaces_list[] = {
 
89
        "MOUNT", "PID", "UTSNAME", "IPC",
 
90
        "USER", "NETWORK"
 
91
};
 
92
static int cloneflags_list[] = {
 
93
        CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
 
94
        CLONE_NEWUSER, CLONE_NEWNET
 
95
};
 
96
 
 
97
static int lxc_namespace_2_cloneflag(char *namespace)
 
98
{
 
99
        int i, len;
 
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];
 
104
 
 
105
        ERROR("invalid namespace name %s", namespace);
 
106
        return -1;
 
107
}
 
108
 
 
109
static int lxc_fill_namespace_flags(char *flaglist, int *flags)
 
110
{
 
111
        char *token, *saveptr = NULL;
 
112
        int aflag;
 
113
 
 
114
        if (!flaglist) {
 
115
                ERROR("need at least one namespace to unshare");
 
116
                return -1;
 
117
        }
 
118
 
 
119
        token = strtok_r(flaglist, "|", &saveptr);
 
120
        while (token) {
 
121
 
 
122
                aflag = lxc_namespace_2_cloneflag(token);
 
123
                if (aflag < 0)
 
124
                        return -1;
 
125
 
 
126
                *flags |= aflag;
 
127
 
 
128
                token = strtok_r(NULL, "|", &saveptr);
 
129
        }
 
130
        return 0;
 
131
}
 
132
 
 
133
 
 
134
struct start_arg {
 
135
        char ***args;
 
136
        int *flags;
 
137
        uid_t *uid;
 
138
};
 
139
 
 
140
static int do_start(void *arg)
 
141
{
 
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;
 
146
 
 
147
        if (flags & CLONE_NEWUSER && setuid(uid)) {
 
148
                ERROR("failed to set uid %d: %s", uid, strerror(errno));
 
149
                exit(1);
 
150
        }
 
151
 
 
152
        execvp(args[0], args);
 
153
 
 
154
        ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
 
155
        return 1;
 
156
}
 
157
 
 
158
int main(int argc, char *argv[])
 
159
{
 
160
        int opt, status;
 
161
        int ret;
 
162
        char *pid_name;
 
163
        char *namespaces = NULL;
 
164
        char **args;
 
165
        int flags = 0;
 
166
        uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */
 
167
        pid_t pid;
 
168
 
 
169
        struct start_arg start_arg = {
 
170
                .args = &args,
 
171
                .uid = &uid,
 
172
                .flags = &flags,
 
173
        };
 
174
 
 
175
        while ((opt = getopt(argc, argv, "s:u:")) != -1) {
 
176
                switch (opt) {
 
177
                case 's':
 
178
                        namespaces = optarg;
 
179
                        break;
 
180
                case 'u':
 
181
                        uid = lookup_user(optarg);
 
182
                        if (uid == -1)
 
183
                                return 1;
 
184
                }
 
185
        }
 
186
 
 
187
        args = &argv[optind];
 
188
 
 
189
        ret = lxc_caps_init();
 
190
        if (ret)
 
191
                return ret;
 
192
 
 
193
        ret = lxc_fill_namespace_flags(namespaces, &flags);
 
194
        if (ret)
 
195
                usage(argv[0]);
 
196
 
 
197
        if (!(flags & CLONE_NEWUSER) && uid != -1) {
 
198
                ERROR("-u <uid> needs -s USER option");
 
199
                return 1;
 
200
        }
 
201
 
 
202
        pid = lxc_clone(do_start, &start_arg, flags);
 
203
        if (pid < 0) {
 
204
                ERROR("failed to clone");
 
205
                return -1;
 
206
        }
 
207
 
 
208
        if (waitpid(pid, &status, 0) < 0) {
 
209
                ERROR("failed to wait for '%d'", pid);
 
210
                return -1;
 
211
        }
 
212
 
 
213
        if (lxc_ns_is_mounted()) {
 
214
                if (asprintf(&pid_name, "%d", pid) == -1) {
 
215
                        ERROR("pid_name: failed to allocate memory");
 
216
                        return -1;
 
217
                }
 
218
                lxc_cgroup_destroy(pid_name);
 
219
                free(pid_name);
 
220
        }
 
221
 
 
222
        return  lxc_error_set_and_log(pid, status);
 
223
}