xref: /freebsd/usr.sbin/jexec/jexec.c (revision b3e76948)
1ebf5d9bcSMike Barcroft /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4ebf5d9bcSMike Barcroft  * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
5413628a7SBjoern A. Zeeb  * Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
6ebf5d9bcSMike Barcroft  * All rights reserved.
7ebf5d9bcSMike Barcroft  *
8ebf5d9bcSMike Barcroft  * Redistribution and use in source and binary forms, with or without
9ebf5d9bcSMike Barcroft  * modification, are permitted provided that the following conditions
10ebf5d9bcSMike Barcroft  * are met:
11ebf5d9bcSMike Barcroft  * 1. Redistributions of source code must retain the above copyright
12ebf5d9bcSMike Barcroft  *    notice, this list of conditions and the following disclaimer.
13ebf5d9bcSMike Barcroft  * 2. Redistributions in binary form must reproduce the above copyright
14ebf5d9bcSMike Barcroft  *    notice, this list of conditions and the following disclaimer in the
15ebf5d9bcSMike Barcroft  *    documentation and/or other materials provided with the distribution.
16ebf5d9bcSMike Barcroft  *
17ebf5d9bcSMike Barcroft  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18ebf5d9bcSMike Barcroft  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19ebf5d9bcSMike Barcroft  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ebf5d9bcSMike Barcroft  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21ebf5d9bcSMike Barcroft  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22ebf5d9bcSMike Barcroft  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23ebf5d9bcSMike Barcroft  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24ebf5d9bcSMike Barcroft  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25ebf5d9bcSMike Barcroft  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26ebf5d9bcSMike Barcroft  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27ebf5d9bcSMike Barcroft  * SUCH DAMAGE.
28ebf5d9bcSMike Barcroft  */
29ebf5d9bcSMike Barcroft 
30ebf5d9bcSMike Barcroft #include <sys/param.h>
31ebf5d9bcSMike Barcroft #include <sys/jail.h>
3273d0971bSJamie Gritton #include <sys/socket.h>
331f406de7SMichael Reifenberger #include <sys/sysctl.h>
341f406de7SMichael Reifenberger 
3573d0971bSJamie Gritton #include <arpa/inet.h>
36413628a7SBjoern A. Zeeb #include <netinet/in.h>
37ebf5d9bcSMike Barcroft 
38ebf5d9bcSMike Barcroft #include <err.h>
3970b75adfSXin LI #include <errno.h>
40de6f3704SJamie Gritton #include <jail.h>
4173d0971bSJamie Gritton #include <limits.h>
4270b75adfSXin LI #include <login_cap.h>
433bbdb8a7SJamie Gritton #include <paths.h>
443bbdb8a7SJamie Gritton #include <pwd.h>
45ebf5d9bcSMike Barcroft #include <stdio.h>
46ebf5d9bcSMike Barcroft #include <stdlib.h>
47413628a7SBjoern A. Zeeb #include <string.h>
48ebf5d9bcSMike Barcroft #include <unistd.h>
49ebf5d9bcSMike Barcroft 
503bbdb8a7SJamie Gritton extern char **environ;
51413628a7SBjoern A. Zeeb 
523bbdb8a7SJamie Gritton static void	get_user_info(const char *username, const struct passwd **pwdp,
533bbdb8a7SJamie Gritton     login_cap_t **lcapp);
543bbdb8a7SJamie Gritton static void	usage(void);
5570b75adfSXin LI 
56ebf5d9bcSMike Barcroft int
main(int argc,char * argv[])57ebf5d9bcSMike Barcroft main(int argc, char *argv[])
58ebf5d9bcSMike Barcroft {
59ebf5d9bcSMike Barcroft 	int jid;
6070b75adfSXin LI 	login_cap_t *lcap = NULL;
613bbdb8a7SJamie Gritton 	int ch, clean, uflag, Uflag;
623bbdb8a7SJamie Gritton 	char *cleanenv;
633bbdb8a7SJamie Gritton 	const struct passwd *pwd = NULL;
643bbdb8a7SJamie Gritton 	const char *username, *shell, *term;
655b4a0a4fSJamie Gritton 
663bbdb8a7SJamie Gritton 	ch = clean = uflag = Uflag = 0;
6773d0971bSJamie Gritton 	username = NULL;
6854404cfbSBrooks Davis 
693bbdb8a7SJamie Gritton 	while ((ch = getopt(argc, argv, "lnu:U:")) != -1) {
7070b75adfSXin LI 		switch (ch) {
713bbdb8a7SJamie Gritton 		case 'l':
723bbdb8a7SJamie Gritton 			clean = 1;
733bbdb8a7SJamie Gritton 			break;
74413628a7SBjoern A. Zeeb 		case 'n':
7573d0971bSJamie Gritton 			/* Specified name, now unused */
76413628a7SBjoern A. Zeeb 			break;
7770b75adfSXin LI 		case 'u':
7870b75adfSXin LI 			username = optarg;
7970b75adfSXin LI 			uflag = 1;
8070b75adfSXin LI 			break;
8170b75adfSXin LI 		case 'U':
8270b75adfSXin LI 			username = optarg;
8370b75adfSXin LI 			Uflag = 1;
8470b75adfSXin LI 			break;
8570b75adfSXin LI 		default:
86ebf5d9bcSMike Barcroft 			usage();
8770b75adfSXin LI 		}
8870b75adfSXin LI 	}
8970b75adfSXin LI 	argc -= optind;
9070b75adfSXin LI 	argv += optind;
913bbdb8a7SJamie Gritton 	if (argc < 1)
9270b75adfSXin LI 		usage();
9370b75adfSXin LI 	if (uflag && Uflag)
9470b75adfSXin LI 		usage();
953bbdb8a7SJamie Gritton 	if (uflag || (clean && !Uflag))
963bbdb8a7SJamie Gritton 		/* User info from the home environment */
973bbdb8a7SJamie Gritton 		get_user_info(username, &pwd, &lcap);
983bbdb8a7SJamie Gritton 
993bbdb8a7SJamie Gritton 	/* Attach to the jail */
100de6f3704SJamie Gritton 	jid = jail_getid(argv[0]);
10173d0971bSJamie Gritton 	if (jid < 0)
102de6f3704SJamie Gritton 		errx(1, "%s", jail_errmsg);
103ebf5d9bcSMike Barcroft 	if (jail_attach(jid) == -1)
104de6f3704SJamie Gritton 		err(1, "jail_attach(%d)", jid);
105ebf5d9bcSMike Barcroft 	if (chdir("/") == -1)
106ebf5d9bcSMike Barcroft 		err(1, "chdir(): /");
1073bbdb8a7SJamie Gritton 
1083bbdb8a7SJamie Gritton 	/* Set up user environment */
1093bbdb8a7SJamie Gritton 	if (clean || username != NULL) {
11070b75adfSXin LI 		if (Uflag)
1113bbdb8a7SJamie Gritton 			/* User info from the jail environment */
1123bbdb8a7SJamie Gritton 			get_user_info(username, &pwd, &lcap);
1133bbdb8a7SJamie Gritton 		if (clean) {
1143bbdb8a7SJamie Gritton 			term = getenv("TERM");
1153bbdb8a7SJamie Gritton 			cleanenv = NULL;
1163bbdb8a7SJamie Gritton 			environ = &cleanenv;
1173bbdb8a7SJamie Gritton 			setenv("PATH", "/bin:/usr/bin", 1);
1183bbdb8a7SJamie Gritton 			if (term != NULL)
1193bbdb8a7SJamie Gritton 				setenv("TERM", term, 1);
1203bbdb8a7SJamie Gritton 		}
12170b75adfSXin LI 		if (setgid(pwd->pw_gid) != 0)
12270b75adfSXin LI 			err(1, "setgid");
1233bbdb8a7SJamie Gritton 		if (setusercontext(lcap, pwd, pwd->pw_uid, username
1243bbdb8a7SJamie Gritton 		    ? LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN
1253bbdb8a7SJamie Gritton 		    : LOGIN_SETPATH | LOGIN_SETENV) != 0)
12670b75adfSXin LI 			err(1, "setusercontext");
12770b75adfSXin LI 		login_close(lcap);
1283bbdb8a7SJamie Gritton 		setenv("USER", pwd->pw_name, 1);
1293bbdb8a7SJamie Gritton 		setenv("HOME", pwd->pw_dir, 1);
1303bbdb8a7SJamie Gritton 		setenv("SHELL",
1313bbdb8a7SJamie Gritton 		    *pwd->pw_shell ? pwd->pw_shell : _PATH_BSHELL, 1);
1323bbdb8a7SJamie Gritton 		if (clean && chdir(pwd->pw_dir) < 0)
1333bbdb8a7SJamie Gritton 			err(1, "chdir: %s", pwd->pw_dir);
1343bbdb8a7SJamie Gritton 		endpwent();
13570b75adfSXin LI 	}
1363bbdb8a7SJamie Gritton 
1373bbdb8a7SJamie Gritton 	/* Run the specified command, or the shell */
1383bbdb8a7SJamie Gritton 	if (argc > 1) {
1393bbdb8a7SJamie Gritton 		if (execvp(argv[1], argv + 1) < 0)
1403bbdb8a7SJamie Gritton 			err(1, "execvp: %s", argv[1]);
1413bbdb8a7SJamie Gritton 	} else {
1423bbdb8a7SJamie Gritton 		if (!(shell = getenv("SHELL")))
1433bbdb8a7SJamie Gritton 			shell = _PATH_BSHELL;
1443bbdb8a7SJamie Gritton 		if (execlp(shell, shell, "-i", NULL) < 0)
1453bbdb8a7SJamie Gritton 			err(1, "execlp: %s", shell);
1463bbdb8a7SJamie Gritton 	}
147ebf5d9bcSMike Barcroft 	exit(0);
148ebf5d9bcSMike Barcroft }
149ebf5d9bcSMike Barcroft 
150ebf5d9bcSMike Barcroft static void
get_user_info(const char * username,const struct passwd ** pwdp,login_cap_t ** lcapp)1513bbdb8a7SJamie Gritton get_user_info(const char *username, const struct passwd **pwdp,
1523bbdb8a7SJamie Gritton     login_cap_t **lcapp)
1533bbdb8a7SJamie Gritton {
1543bbdb8a7SJamie Gritton 	uid_t uid;
1553bbdb8a7SJamie Gritton 	const struct passwd *pwd;
1563bbdb8a7SJamie Gritton 
1573bbdb8a7SJamie Gritton 	errno = 0;
1583bbdb8a7SJamie Gritton 	if (username) {
1593bbdb8a7SJamie Gritton 		pwd = getpwnam(username);
1603bbdb8a7SJamie Gritton 		if (pwd == NULL) {
1613bbdb8a7SJamie Gritton 			if (errno)
1623bbdb8a7SJamie Gritton 				err(1, "getpwnam: %s", username);
1633bbdb8a7SJamie Gritton 			else
1643bbdb8a7SJamie Gritton 				errx(1, "%s: no such user", username);
1653bbdb8a7SJamie Gritton 		}
1663bbdb8a7SJamie Gritton 	} else {
1673bbdb8a7SJamie Gritton 		uid = getuid();
1683bbdb8a7SJamie Gritton 		pwd = getpwuid(uid);
1693bbdb8a7SJamie Gritton 		if (pwd == NULL) {
1703bbdb8a7SJamie Gritton 			if (errno)
1713bbdb8a7SJamie Gritton 				err(1, "getpwuid: %d", uid);
1723bbdb8a7SJamie Gritton 			else
1733bbdb8a7SJamie Gritton 				errx(1, "unknown uid: %d", uid);
1743bbdb8a7SJamie Gritton 		}
1753bbdb8a7SJamie Gritton 	}
1763bbdb8a7SJamie Gritton 	*pwdp = pwd;
1773bbdb8a7SJamie Gritton 	*lcapp = login_getpwclass(pwd);
1783bbdb8a7SJamie Gritton 	if (*lcapp == NULL)
1793bbdb8a7SJamie Gritton 		err(1, "getpwclass: %s", pwd->pw_name);
1803bbdb8a7SJamie Gritton 	if (initgroups(pwd->pw_name, pwd->pw_gid) < 0)
1813bbdb8a7SJamie Gritton 		err(1, "initgroups: %s", pwd->pw_name);
1823bbdb8a7SJamie Gritton }
1833bbdb8a7SJamie Gritton 
1843bbdb8a7SJamie Gritton static void
usage(void)185ebf5d9bcSMike Barcroft usage(void)
186ebf5d9bcSMike Barcroft {
187ebf5d9bcSMike Barcroft 
18873d0971bSJamie Gritton 	fprintf(stderr, "%s\n",
1893bbdb8a7SJamie Gritton 	    "usage: jexec [-l] [-u username | -U username] jail [command ...]");
190ebf5d9bcSMike Barcroft 	exit(1);
191ebf5d9bcSMike Barcroft }
192