2 * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
3 * Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
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>
32 #include <sys/sysctl.h>
34 #include <netinet/in.h>
38 #include <login_cap.h>
45 static void usage(void);
47 #ifdef SUPPORT_OLD_XPRISON
49 char *lookup_xprison_v1(void *p, char *end, int *id)
51 struct xprison_v1 *xp;
54 errx(1, "Internal error. Invalid ID pointer.");
56 if ((char *)p + sizeof(struct xprison_v1) > end)
57 errx(1, "Invalid length for jail");
59 xp = (struct xprison_v1 *)p;
62 return ((char *)(xp + 1));
67 char *lookup_xprison_v3(void *p, char *end, int *id, char *jailname)
74 errx(1, "Internal error. Invalid ID pointer.");
76 if ((char *)p + sizeof(struct xprison) > end)
77 errx(1, "Invalid length for jail");
79 xp = (struct xprison *)p;
82 /* Jail state and name. */
83 if (xp->pr_state < 0 || xp->pr_state >=
84 (int)((sizeof(prison_states) / sizeof(struct prison_state))))
85 errx(1, "Invalid jail state.");
86 else if (xp->pr_state != PRISON_STATE_ALIVE)
88 if (jailname != NULL) {
89 if (xp->pr_name[0] == '\0')
91 else if (strcmp(jailname, xp->pr_name) != 0)
97 q += (xp->pr_ip4s * sizeof(struct in_addr));
99 errx(1, "Invalid length for jail");
100 /* IPv6 addresses. */
101 q += (xp->pr_ip6s * sizeof(struct in6_addr));
103 errx(1, "Invalid length for jail");
111 lookup_jail(int jid, char *jailname)
115 int version, id, xid, count;
117 if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
118 err(1, "sysctlbyname(): security.jail.list");
121 for (i = 0; i < 4; i++) {
128 if (sysctlbyname("security.jail.list", q, &len, NULL, 0) == -1) {
129 if (errno == ENOMEM) {
135 err(1, "sysctlbyname(): security.jail.list");
140 err(1, "sysctlbyname(): security.jail.list");
141 if (len < sizeof(int))
142 errx(1, "This is no prison. Kernel and userland out of sync?");
144 if (version > XPRISON_VERSION)
145 errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
149 for (; q != NULL && (char *)q + sizeof(int) < (char *)p + len;) {
151 if (version > XPRISON_VERSION)
152 errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
155 #ifdef SUPPORT_OLD_XPRISON
157 if (jailname != NULL)
158 errx(1, "Version 1 prisons did not "
159 "support jail names.");
160 q = lookup_xprison_v1(q, (char *)p + len, &id);
163 errx(1, "Version 2 was used by multi-IPv4 jail "
164 "implementations that never made it into the "
170 q = lookup_xprison_v3(q, (char *)p + len, &id, jailname);
173 errx(1, "Prison unknown. Kernel/userland out of sync?");
177 /* Possible match; see if we have a jail ID to match as well. */
178 if (id > 0 && (jid <= 0 || id == jid)) {
189 errx(1, "Could not uniquely identify the jail.");
194 #define GET_USER_INFO do { \
195 pwd = getpwnam(username); \
198 err(1, "getpwnam: %s", username); \
200 errx(1, "%s: no such user", username); \
202 lcap = login_getpwclass(pwd); \
204 err(1, "getpwclass: %s", username); \
206 if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0) \
207 err(1, "getgrouplist: %s", username); \
211 main(int argc, char *argv[])
214 login_cap_t *lcap = NULL;
215 struct passwd *pwd = NULL;
216 gid_t groups[NGROUPS];
217 int ch, ngroups, uflag, Uflag;
218 char *jailname, *username;
220 ch = uflag = Uflag = 0;
221 jailname = username = NULL;
224 while ((ch = getopt(argc, argv, "i:n:u:U:")) != -1) {
245 if (strlen(argv[0]) > 0) {
246 jid = (int)strtol(argv[0], NULL, 10);
248 err(1, "Unable to parse jail ID.");
250 if (jid <= 0 && jailname == NULL) {
251 fprintf(stderr, "Neither jail ID nor jail name given.\n");
258 jid = lookup_jail(jid, jailname);
260 errx(1, "Cannot identify jail.");
261 if (jail_attach(jid) == -1)
262 err(1, "jail_attach(): %d", jid);
263 if (chdir("/") == -1)
264 err(1, "chdir(): /");
265 if (username != NULL) {
268 if (setgroups(ngroups, groups) != 0)
270 if (setgid(pwd->pw_gid) != 0)
272 if (setusercontext(lcap, pwd, pwd->pw_uid,
273 LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0)
274 err(1, "setusercontext");
277 if (execvp(argv[1], argv + 1) == -1)
278 err(1, "execvp(): %s", argv[1]);
286 fprintf(stderr, "%s%s\n",
287 "usage: jexec [-u username | -U username]",
288 " [-n jailname] jid command ...");