2 * Copyright (c) 2002-2004 Marko Zec <zec@fer.hr>
3 * Copyright (c) 2009 University of Zagreb
4 * Copyright (c) 2009 FreeBSD Foundation
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/param.h>
31 #include <sys/ioctl.h>
33 #include <sys/socket.h>
53 typedef struct vimage_status {
54 char name[MAXPATHLEN]; /* Must be first field for strcmp(). */
55 char path[MAXPATHLEN];
56 char hostname[MAXPATHLEN];
57 char domainname[MAXPATHLEN];
69 #define VST_SIZE_STEP 1024
72 static int getjail(vstat_t *, int, int);
74 static char *invocname;
81 "usage: %s [-c | -m] vname [param=value ...]\n"
83 " %s -l[rvj] [vname]\n"
84 " %s -i vname ifname [newifname]\n"
85 " %s vname [command ...]\n",
86 invocname, invocname, invocname, invocname, invocname);
91 main(int argc, char **argv)
93 struct jailparam params[MAXPARAMS];
94 char ifname[IFNAMSIZ];
99 int jid, i, s, namelen;
100 int vst_size, vst_last;
107 newcmd = cmd = VI_SWITCHTO; /* Default if no modifiers specified. */
108 while ((ch = getopt(argc, argv, "cdijlmrv")) != -1) {
137 if (cmd == VI_SWITCHTO || cmd == newcmd)
145 if ((cmd != VI_GET && (argc == 0 || recurse != 0 || verbose != 0)) ||
146 (cmd == VI_IFMOVE && (argc < 2 || argc > 3)) ||
147 (cmd == VI_MODIFY && argc < 2) || argc >= MAXPARAMS)
153 vst_size = VST_SIZE_STEP;
154 if ((vst = malloc(vst_size * sizeof(*vst))) == NULL)
157 namelen = strlen(argv[0]);
161 while ((jid = getjail(&vst[vst_last], jid, verbose)) > 0) {
162 /* Skip jails which do not own vnets. */
163 if (vst[vst_last].vnet != 1)
165 /* Skip non-matching vnames / hierarchies. */
167 ((strlen(vst[vst_last].name) < namelen ||
168 strncmp(vst[vst_last].name, argv[0], namelen) != 0)
169 || (strlen(vst[vst_last].name) > namelen &&
170 vst[vst_last].name[namelen] != '.')))
172 /* Skip any sub-trees if -r not requested. */
174 (strlen(vst[vst_last].name) < namelen ||
175 strchr(&vst[vst_last].name[namelen], '.') != NULL))
177 /* Grow vst table if necessary. */
178 if (++vst_last == vst_size) {
179 vst_size += VST_SIZE_STEP;
180 vst = realloc(vst, vst_size * sizeof(*vst));
187 /* Sort: the key is the 1st field in *vst, i.e. vimage name. */
188 qsort(vst, vst_last, sizeof(*vst), (void *) strcmp);
189 for (i = 0; i < vst_last; i++) {
191 printf("%s\n", vst[i].name);
195 printf("%s:\n", vst[i].name);
196 printf(" Path: %s\n", vst[i].path);
197 printf(" Hostname: %s\n", vst[i].hostname);
198 printf(" Domainname: %s\n", vst[i].domainname);
199 printf(" Children: %d\n", vst[i].childcnt);
204 printf(" Children limit: %d\n", vst[i].childmax);
205 printf(" CPUsetID: %d\n", vst[i].cpuset);
206 printf(" JID: %d\n", vst[i].jid);
207 printf(" PJID: %d\n", vst[i].parentjid);
208 printf(" Raw sockets allowed: %d\n", vst[i].rawsock);
209 printf(" All AF allowed: %d\n", vst[i].socket_af);
210 printf(" Mount allowed: %d\n", vst[i].mount);
216 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
218 if ((jid = jail_getid(argv[0])) < 0)
221 strncpy(ifreq.ifr_name, argv[1], sizeof(ifreq.ifr_name));
222 if (ioctl(s, SIOCSIFVNET, (caddr_t)&ifreq) < 0)
226 snprintf(ifname, sizeof(ifname), "%s", argv[2]);
228 snprintf(ifname, sizeof(ifname), "eth0");
229 ifreq.ifr_data = ifname;
230 /* Do we need to rename the ifnet? */
231 if (strcmp(ifreq.ifr_name, ifname) != 0) {
232 /* Switch to the context of the target vimage. */
233 if (jail_attach(jid) < 0)
235 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
237 for (namelen = 0; isalpha(ifname[namelen]); namelen++);
239 /* Search for a free ifunit in target vnet. Unsafe. */
240 while (ioctl(s, SIOCSIFNAME, (caddr_t)&ifreq) < 0) {
241 snprintf(&ifname[namelen],
242 sizeof(ifname) - namelen, "%d", i);
243 /* Emergency brake. */
244 if (i++ == IF_MAXUNIT)
249 printf("%s@%s\n", ifname, argv[0]);
251 printf("%s@%s\n", ifreq.ifr_name, argv[0]);
255 if (jail_setv(JAIL_CREATE,
260 "allow.raw_sockets", "true",
261 "allow.socket_af", "true",
262 "allow.mount", "true",
267 /* Not done yet, proceed to apply non-default parameters. */
270 jailparam_init(¶ms[0], "name");
271 jailparam_import(¶ms[0], argv[0]);
272 for (i = 1; i < argc; i++) {
273 for (str = argv[i]; *str != '=' && *str != 0; str++) {
274 /* Do nothing - search for '=' delimeter. */
281 jailparam_init(¶ms[i], argv[i]);
282 jailparam_import(¶ms[i], str);
286 if (jailparam_set(params, i, JAIL_UPDATE) < 0)
291 if ((jid = jail_getid(argv[0])) < 0)
293 if (jail_remove(jid) < 0)
298 if ((jid = jail_getid(argv[0])) < 0)
300 if (jail_attach(jid) < 0)
303 printf("Switched to vimage %s\n", argv[0]);
304 if ((str = getenv("SHELL")) == NULL)
305 execlp("/bin/sh", invocname, NULL);
307 execlp(str, invocname, NULL);
309 execvp(argv[1], &argv[1]);
313 /* Should be unreachable. */
318 fprintf(stderr, "Error: %s\n", jail_errmsg);
325 getjail(vstat_t *vs, int lastjid, int verbose)
327 struct jailparam params[32]; /* Must be > max(psize). */
330 bzero(params, sizeof(params));
331 bzero(vs, sizeof(*vs));
333 jailparam_init(¶ms[psize], "lastjid");
334 jailparam_import_raw(¶ms[psize++], &lastjid, sizeof lastjid);
336 jailparam_init(¶ms[psize], "vnet");
337 jailparam_import_raw(¶ms[psize++], &vs->vnet, sizeof(vs->vnet));
339 jailparam_init(¶ms[psize], "name");
340 jailparam_import_raw(¶ms[psize++], &vs->name, sizeof(vs->name));
345 jailparam_init(¶ms[psize], "path");
346 jailparam_import_raw(¶ms[psize++], &vs->path, sizeof(vs->path));
348 jailparam_init(¶ms[psize], "host.hostname");
349 jailparam_import_raw(¶ms[psize++], &vs->hostname,
350 sizeof(vs->hostname));
352 jailparam_init(¶ms[psize], "host.domainname");
353 jailparam_import_raw(¶ms[psize++], &vs->domainname,
354 sizeof(vs->domainname));
356 jailparam_init(¶ms[psize], "children.cur");
357 jailparam_import_raw(¶ms[psize++], &vs->childcnt,
358 sizeof(vs->childcnt));
363 jailparam_init(¶ms[psize], "children.max");
364 jailparam_import_raw(¶ms[psize++], &vs->childmax,
365 sizeof(vs->childmax));
367 jailparam_init(¶ms[psize], "cpuset.id");
368 jailparam_import_raw(¶ms[psize++], &vs->cpuset,
371 jailparam_init(¶ms[psize], "parent");
372 jailparam_import_raw(¶ms[psize++], &vs->parentjid,
373 sizeof(vs->parentjid));
375 jailparam_init(¶ms[psize], "allow.raw_sockets");
376 jailparam_import_raw(¶ms[psize++], &vs->rawsock,
377 sizeof(vs->rawsock));
379 jailparam_init(¶ms[psize], "allow.socket_af");
380 jailparam_import_raw(¶ms[psize++], &vs->socket_af,
381 sizeof(vs->socket_af));
383 jailparam_init(¶ms[psize], "allow.mount");
384 jailparam_import_raw(¶ms[psize++], &vs->mount, sizeof(vs->mount));
387 vs->jid = jailparam_get(params, psize, 0);
388 jailparam_free(params, psize);