]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_unshare.c
licensing: Add missing headers and FSF address
[mirror_lxc.git] / src / lxc / lxc_unshare.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 char name[sysconf(_SC_LOGIN_NAME_MAX)];
58 uid_t uid = -1;
59 struct passwd *pwent = NULL;
60
61 if (!optarg || (optarg[0] == '\0'))
62 return uid;
63
64 if (sscanf(optarg, "%u", &uid) < 1) {
65 /* not a uid -- perhaps a username */
66 if (sscanf(optarg, "%s", name) < 1)
67 return uid;
68
69 pwent = getpwnam(name);
70 if (!pwent) {
71 ERROR("invalid username %s", name);
72 return uid;
73 }
74 uid = pwent->pw_uid;
75 } else {
76 pwent = getpwuid(uid);
77 if (!pwent) {
78 ERROR("invalid uid %d", uid);
79 uid = -1;
80 return uid;
81 }
82 }
83 return uid;
84 }
85
86
87 struct start_arg {
88 char ***args;
89 int *flags;
90 uid_t *uid;
91 };
92
93 static int do_start(void *arg)
94 {
95 struct start_arg *start_arg = arg;
96 char **args = *start_arg->args;
97 int flags = *start_arg->flags;
98 uid_t uid = *start_arg->uid;
99
100 if (flags & CLONE_NEWUSER && setuid(uid)) {
101 ERROR("failed to set uid %d: %s", uid, strerror(errno));
102 exit(1);
103 }
104
105 execvp(args[0], args);
106
107 ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
108 return 1;
109 }
110
111 int main(int argc, char *argv[])
112 {
113 int opt, status;
114 int ret;
115 char *namespaces = NULL;
116 char **args;
117 int flags = 0;
118 uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */
119 pid_t pid;
120
121 struct start_arg start_arg = {
122 .args = &args,
123 .uid = &uid,
124 .flags = &flags,
125 };
126
127 while ((opt = getopt(argc, argv, "s:u:h")) != -1) {
128 switch (opt) {
129 case 's':
130 namespaces = optarg;
131 break;
132 case 'h':
133 usage(argv[0]);
134 case 'u':
135 uid = lookup_user(optarg);
136 if (uid == -1)
137 return 1;
138 }
139 }
140
141 if (argv[optind] == NULL) {
142 ERROR("a command to execute in the new namespace is required");
143 return 1;
144 }
145
146 args = &argv[optind];
147
148 ret = lxc_caps_init();
149 if (ret)
150 return ret;
151
152 ret = lxc_fill_namespace_flags(namespaces, &flags);
153 if (ret)
154 usage(argv[0]);
155
156 if (!(flags & CLONE_NEWUSER) && uid != -1) {
157 ERROR("-u <uid> needs -s USER option");
158 return 1;
159 }
160
161 pid = lxc_clone(do_start, &start_arg, flags);
162 if (pid < 0) {
163 ERROR("failed to clone");
164 return -1;
165 }
166
167 if (waitpid(pid, &status, 0) < 0) {
168 ERROR("failed to wait for '%d'", pid);
169 return -1;
170 }
171
172 return lxc_error_set_and_log(pid, status);
173 }