jexec.c revision 194709
1/*-
2 * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
3 * Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 *
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
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/usr.sbin/jexec/jexec.c 194709 2009-06-23 14:40:08Z jamie $
28 */
29
30#include <sys/param.h>
31#include <sys/jail.h>
32#include <sys/socket.h>
33#include <sys/sysctl.h>
34#include <sys/uio.h>
35
36#include <arpa/inet.h>
37#include <netinet/in.h>
38
39#include <err.h>
40#include <errno.h>
41#include <limits.h>
42#include <login_cap.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <pwd.h>
47#include <unistd.h>
48
49static void	usage(void);
50
51#define GET_USER_INFO do {						\
52	pwd = getpwnam(username);					\
53	if (pwd == NULL) {						\
54		if (errno)						\
55			err(1, "getpwnam: %s", username);		\
56		else							\
57			errx(1, "%s: no such user", username);		\
58	}								\
59	lcap = login_getpwclass(pwd);					\
60	if (lcap == NULL)						\
61		err(1, "getpwclass: %s", username);			\
62	ngroups = ngroups_max;						\
63	if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0)	\
64		err(1, "getgrouplist: %s", username);			\
65} while (0)
66
67int
68main(int argc, char *argv[])
69{
70	struct iovec params[2];
71	int jid;
72	login_cap_t *lcap = NULL;
73	struct passwd *pwd = NULL;
74	gid_t *groups = NULL;
75	int ch, ngroups, uflag, Uflag;
76	long ngroups_max;
77	char *ep, *username;
78
79	ch = uflag = Uflag = 0;
80	username = NULL;
81	ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1;
82	if ((groups = malloc(sizeof(gid_t) * ngroups_max)) == NULL)
83		err(1, "malloc");
84
85	while ((ch = getopt(argc, argv, "nu:U:")) != -1) {
86		switch (ch) {
87		case 'n':
88			/* Specified name, now unused */
89			break;
90		case 'u':
91			username = optarg;
92			uflag = 1;
93			break;
94		case 'U':
95			username = optarg;
96			Uflag = 1;
97			break;
98		default:
99			usage();
100		}
101	}
102	argc -= optind;
103	argv += optind;
104	if (argc < 2)
105		usage();
106	if (uflag && Uflag)
107		usage();
108	if (uflag)
109		GET_USER_INFO;
110	jid = strtoul(argv[0], &ep, 10);
111	if (!*argv[0] || *ep) {
112		*(const void **)&params[0].iov_base = "name";
113		params[0].iov_len = sizeof("name");
114		params[1].iov_base = argv[0];
115		params[1].iov_len = strlen(argv[0]) + 1;
116		jid = jail_get(params, 2, 0);
117		if (jid < 0)
118			errx(1, "Unknown jail: %s", argv[0]);
119	}
120	if (jail_attach(jid) == -1)
121		err(1, "jail_attach(): %d", jid);
122	if (chdir("/") == -1)
123		err(1, "chdir(): /");
124	if (username != NULL) {
125		if (Uflag)
126			GET_USER_INFO;
127		if (setgroups(ngroups, groups) != 0)
128			err(1, "setgroups");
129		if (setgid(pwd->pw_gid) != 0)
130			err(1, "setgid");
131		if (setusercontext(lcap, pwd, pwd->pw_uid,
132		    LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0)
133			err(1, "setusercontext");
134		login_close(lcap);
135	}
136	if (execvp(argv[1], argv + 1) == -1)
137		err(1, "execvp(): %s", argv[1]);
138	exit(0);
139}
140
141static void
142usage(void)
143{
144
145	fprintf(stderr, "%s\n",
146		"usage: jexec [-u username | -U username] jail command ...");
147	exit(1);
148}
149