1113277Smike/*-
2113277Smike * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
3185435Sbz * Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
4113277Smike * All rights reserved.
5113277Smike *
6113277Smike * Redistribution and use in source and binary forms, with or without
7113277Smike * modification, are permitted provided that the following conditions
8113277Smike * are met:
9113277Smike * 1. Redistributions of source code must retain the above copyright
10113277Smike *    notice, this list of conditions and the following disclaimer.
11113277Smike * 2. Redistributions in binary form must reproduce the above copyright
12113277Smike *    notice, this list of conditions and the following disclaimer in the
13113277Smike *    documentation and/or other materials provided with the distribution.
14113277Smike *
15113277Smike * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16113277Smike * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17113277Smike * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18113277Smike * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19113277Smike * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20113277Smike * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21113277Smike * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22113277Smike * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23113277Smike * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24113277Smike * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25113277Smike * SUCH DAMAGE.
26113277Smike *
27113277Smike * $FreeBSD: releng/10.3/usr.sbin/jexec/jexec.c 286064 2015-07-30 04:53:53Z jamie $
28113277Smike */
29113277Smike
30113277Smike#include <sys/param.h>
31113277Smike#include <sys/jail.h>
32192896Sjamie#include <sys/socket.h>
33179319Smr#include <sys/sysctl.h>
34113277Smike
35192896Sjamie#include <arpa/inet.h>
36185435Sbz#include <netinet/in.h>
37179319Smr
38113277Smike#include <err.h>
39157864Sdelphij#include <errno.h>
40194869Sjamie#include <jail.h>
41192896Sjamie#include <limits.h>
42157864Sdelphij#include <login_cap.h>
43286064Sjamie#include <paths.h>
44286064Sjamie#include <pwd.h>
45113277Smike#include <stdio.h>
46113277Smike#include <stdlib.h>
47185435Sbz#include <string.h>
48113277Smike#include <unistd.h>
49113277Smike
50286064Sjamieextern char **environ;
51286064Sjamie
52286064Sjamiestatic void	get_user_info(const char *username, const struct passwd **pwdp,
53286064Sjamie    login_cap_t **lcapp);
54113277Smikestatic void	usage(void);
55113277Smike
56113277Smikeint
57113277Smikemain(int argc, char *argv[])
58113277Smike{
59113277Smike	int jid;
60157864Sdelphij	login_cap_t *lcap = NULL;
61286064Sjamie	int ch, clean, uflag, Uflag;
62286064Sjamie	char *cleanenv;
63286064Sjamie	const struct passwd *pwd = NULL;
64286064Sjamie	const char *username, *shell, *term;
65194709Sjamie
66286064Sjamie	ch = clean = uflag = Uflag = 0;
67192896Sjamie	username = NULL;
68194494Sbrooks
69286064Sjamie	while ((ch = getopt(argc, argv, "lnu:U:")) != -1) {
70157864Sdelphij		switch (ch) {
71286064Sjamie		case 'l':
72286064Sjamie			clean = 1;
73286064Sjamie			break;
74185435Sbz		case 'n':
75192896Sjamie			/* Specified name, now unused */
76185435Sbz			break;
77157864Sdelphij		case 'u':
78157864Sdelphij			username = optarg;
79157864Sdelphij			uflag = 1;
80157864Sdelphij			break;
81157864Sdelphij		case 'U':
82157864Sdelphij			username = optarg;
83157864Sdelphij			Uflag = 1;
84157864Sdelphij			break;
85157864Sdelphij		default:
86157864Sdelphij			usage();
87157864Sdelphij		}
88157864Sdelphij	}
89157864Sdelphij	argc -= optind;
90157864Sdelphij	argv += optind;
91286064Sjamie	if (argc < 1)
92113277Smike		usage();
93157864Sdelphij	if (uflag && Uflag)
94157864Sdelphij		usage();
95286064Sjamie	if (uflag || (clean && !Uflag))
96286064Sjamie		/* User info from the home environment */
97286064Sjamie		get_user_info(username, &pwd, &lcap);
98286064Sjamie
99286064Sjamie	/* Attach to the jail */
100194869Sjamie	jid = jail_getid(argv[0]);
101194869Sjamie	if (jid < 0)
102194869Sjamie		errx(1, "%s", jail_errmsg);
103113277Smike	if (jail_attach(jid) == -1)
104194869Sjamie		err(1, "jail_attach(%d)", jid);
105113277Smike	if (chdir("/") == -1)
106113277Smike		err(1, "chdir(): /");
107286064Sjamie
108286064Sjamie	/* Set up user environment */
109286064Sjamie	if (clean || username != NULL) {
110157864Sdelphij		if (Uflag)
111286064Sjamie			/* User info from the jail environment */
112286064Sjamie			get_user_info(username, &pwd, &lcap);
113286064Sjamie		if (clean) {
114286064Sjamie			term = getenv("TERM");
115286064Sjamie			cleanenv = NULL;
116286064Sjamie			environ = &cleanenv;
117286064Sjamie			setenv("PATH", "/bin:/usr/bin", 1);
118286064Sjamie			if (term != NULL)
119286064Sjamie				setenv("TERM", term, 1);
120286064Sjamie		}
121157864Sdelphij		if (setgid(pwd->pw_gid) != 0)
122157864Sdelphij			err(1, "setgid");
123286064Sjamie		if (setusercontext(lcap, pwd, pwd->pw_uid, username
124286064Sjamie		    ? LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN
125286064Sjamie		    : LOGIN_SETPATH | LOGIN_SETENV) != 0)
126157864Sdelphij			err(1, "setusercontext");
127157864Sdelphij		login_close(lcap);
128286064Sjamie		setenv("USER", pwd->pw_name, 1);
129286064Sjamie		setenv("HOME", pwd->pw_dir, 1);
130286064Sjamie		setenv("SHELL",
131286064Sjamie		    *pwd->pw_shell ? pwd->pw_shell : _PATH_BSHELL, 1);
132286064Sjamie		if (clean && chdir(pwd->pw_dir) < 0)
133286064Sjamie			err(1, "chdir: %s", pwd->pw_dir);
134286064Sjamie		endpwent();
135157864Sdelphij	}
136286064Sjamie
137286064Sjamie	/* Run the specified command, or the shell */
138286064Sjamie	if (argc > 1) {
139286064Sjamie		if (execvp(argv[1], argv + 1) < 0)
140286064Sjamie			err(1, "execvp: %s", argv[1]);
141286064Sjamie	} else {
142286064Sjamie		if (!(shell = getenv("SHELL")))
143286064Sjamie			shell = _PATH_BSHELL;
144286064Sjamie		if (execlp(shell, shell, "-i", NULL) < 0)
145286064Sjamie			err(1, "execlp: %s", shell);
146286064Sjamie	}
147113277Smike	exit(0);
148113277Smike}
149113277Smike
150113277Smikestatic void
151286064Sjamieget_user_info(const char *username, const struct passwd **pwdp,
152286064Sjamie    login_cap_t **lcapp)
153286064Sjamie{
154286064Sjamie	uid_t uid;
155286064Sjamie	const struct passwd *pwd;
156286064Sjamie
157286064Sjamie	errno = 0;
158286064Sjamie	if (username) {
159286064Sjamie		pwd = getpwnam(username);
160286064Sjamie		if (pwd == NULL) {
161286064Sjamie			if (errno)
162286064Sjamie				err(1, "getpwnam: %s", username);
163286064Sjamie			else
164286064Sjamie				errx(1, "%s: no such user", username);
165286064Sjamie		}
166286064Sjamie	} else {
167286064Sjamie		uid = getuid();
168286064Sjamie		pwd = getpwuid(uid);
169286064Sjamie		if (pwd == NULL) {
170286064Sjamie			if (errno)
171286064Sjamie				err(1, "getpwuid: %d", uid);
172286064Sjamie			else
173286064Sjamie				errx(1, "unknown uid: %d", uid);
174286064Sjamie		}
175286064Sjamie	}
176286064Sjamie	*pwdp = pwd;
177286064Sjamie	*lcapp = login_getpwclass(pwd);
178286064Sjamie	if (*lcapp == NULL)
179286064Sjamie		err(1, "getpwclass: %s", pwd->pw_name);
180286064Sjamie	if (initgroups(pwd->pw_name, pwd->pw_gid) < 0)
181286064Sjamie		err(1, "initgroups: %s", pwd->pw_name);
182286064Sjamie}
183286064Sjamie
184286064Sjamiestatic void
185113277Smikeusage(void)
186113277Smike{
187113277Smike
188192896Sjamie	fprintf(stderr, "%s\n",
189286064Sjamie	    "usage: jexec [-l] [-u username | -U username] jail [command ...]");
190113277Smike	exit(1);
191113277Smike}
192