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;
61*d56f3b05SJamie Gritton int ch, clean, dflag, uflag, Uflag;
623bbdb8a7SJamie Gritton char *cleanenv;
633bbdb8a7SJamie Gritton const struct passwd *pwd = NULL;
643bbdb8a7SJamie Gritton const char *username, *shell, *term;
65*d56f3b05SJamie Gritton const char *workdir;
665b4a0a4fSJamie Gritton
67*d56f3b05SJamie Gritton ch = clean = dflag = uflag = Uflag = 0;
6873d0971bSJamie Gritton username = NULL;
69*d56f3b05SJamie Gritton workdir = "/";
7054404cfbSBrooks Davis
71*d56f3b05SJamie Gritton while ((ch = getopt(argc, argv, "d:lnu:U:")) != -1) {
7270b75adfSXin LI switch (ch) {
73*d56f3b05SJamie Gritton case 'd':
74*d56f3b05SJamie Gritton workdir = optarg;
75*d56f3b05SJamie Gritton dflag = 1;
76*d56f3b05SJamie Gritton break;
773bbdb8a7SJamie Gritton case 'l':
783bbdb8a7SJamie Gritton clean = 1;
793bbdb8a7SJamie Gritton break;
80413628a7SBjoern A. Zeeb case 'n':
8173d0971bSJamie Gritton /* Specified name, now unused */
82413628a7SBjoern A. Zeeb break;
8370b75adfSXin LI case 'u':
8470b75adfSXin LI username = optarg;
8570b75adfSXin LI uflag = 1;
8670b75adfSXin LI break;
8770b75adfSXin LI case 'U':
8870b75adfSXin LI username = optarg;
8970b75adfSXin LI Uflag = 1;
9070b75adfSXin LI break;
9170b75adfSXin LI default:
92ebf5d9bcSMike Barcroft usage();
9370b75adfSXin LI }
9470b75adfSXin LI }
9570b75adfSXin LI argc -= optind;
9670b75adfSXin LI argv += optind;
973bbdb8a7SJamie Gritton if (argc < 1)
9870b75adfSXin LI usage();
9970b75adfSXin LI if (uflag && Uflag)
10070b75adfSXin LI usage();
1013bbdb8a7SJamie Gritton if (uflag || (clean && !Uflag))
1023bbdb8a7SJamie Gritton /* User info from the home environment */
1033bbdb8a7SJamie Gritton get_user_info(username, &pwd, &lcap);
1043bbdb8a7SJamie Gritton
1053bbdb8a7SJamie Gritton /* Attach to the jail */
106de6f3704SJamie Gritton jid = jail_getid(argv[0]);
10773d0971bSJamie Gritton if (jid < 0)
108de6f3704SJamie Gritton errx(1, "%s", jail_errmsg);
109ebf5d9bcSMike Barcroft if (jail_attach(jid) == -1)
110de6f3704SJamie Gritton err(1, "jail_attach(%d)", jid);
111*d56f3b05SJamie Gritton if (chdir(workdir) == -1)
112*d56f3b05SJamie Gritton err(1, "chdir(): %s", workdir);
1133bbdb8a7SJamie Gritton
1143bbdb8a7SJamie Gritton /* Set up user environment */
1153bbdb8a7SJamie Gritton if (clean || username != NULL) {
11670b75adfSXin LI if (Uflag)
1173bbdb8a7SJamie Gritton /* User info from the jail environment */
1183bbdb8a7SJamie Gritton get_user_info(username, &pwd, &lcap);
1193bbdb8a7SJamie Gritton if (clean) {
1203bbdb8a7SJamie Gritton term = getenv("TERM");
1213bbdb8a7SJamie Gritton cleanenv = NULL;
1223bbdb8a7SJamie Gritton environ = &cleanenv;
1233bbdb8a7SJamie Gritton setenv("PATH", "/bin:/usr/bin", 1);
1243bbdb8a7SJamie Gritton if (term != NULL)
1253bbdb8a7SJamie Gritton setenv("TERM", term, 1);
1263bbdb8a7SJamie Gritton }
12770b75adfSXin LI if (setgid(pwd->pw_gid) != 0)
12870b75adfSXin LI err(1, "setgid");
1293bbdb8a7SJamie Gritton if (setusercontext(lcap, pwd, pwd->pw_uid, username
1303bbdb8a7SJamie Gritton ? LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN
1313bbdb8a7SJamie Gritton : LOGIN_SETPATH | LOGIN_SETENV) != 0)
13270b75adfSXin LI err(1, "setusercontext");
13370b75adfSXin LI login_close(lcap);
1343bbdb8a7SJamie Gritton setenv("USER", pwd->pw_name, 1);
1353bbdb8a7SJamie Gritton setenv("HOME", pwd->pw_dir, 1);
1363bbdb8a7SJamie Gritton setenv("SHELL",
1373bbdb8a7SJamie Gritton *pwd->pw_shell ? pwd->pw_shell : _PATH_BSHELL, 1);
138*d56f3b05SJamie Gritton if (clean && username && !dflag && chdir(pwd->pw_dir) < 0)
1393bbdb8a7SJamie Gritton err(1, "chdir: %s", pwd->pw_dir);
1403bbdb8a7SJamie Gritton endpwent();
14170b75adfSXin LI }
1423bbdb8a7SJamie Gritton
1433bbdb8a7SJamie Gritton /* Run the specified command, or the shell */
1443bbdb8a7SJamie Gritton if (argc > 1) {
1453bbdb8a7SJamie Gritton if (execvp(argv[1], argv + 1) < 0)
1463bbdb8a7SJamie Gritton err(1, "execvp: %s", argv[1]);
1473bbdb8a7SJamie Gritton } else {
1483bbdb8a7SJamie Gritton if (!(shell = getenv("SHELL")))
1493bbdb8a7SJamie Gritton shell = _PATH_BSHELL;
1503bbdb8a7SJamie Gritton if (execlp(shell, shell, "-i", NULL) < 0)
1513bbdb8a7SJamie Gritton err(1, "execlp: %s", shell);
1523bbdb8a7SJamie Gritton }
153ebf5d9bcSMike Barcroft exit(0);
154ebf5d9bcSMike Barcroft }
155ebf5d9bcSMike Barcroft
156ebf5d9bcSMike Barcroft static void
get_user_info(const char * username,const struct passwd ** pwdp,login_cap_t ** lcapp)1573bbdb8a7SJamie Gritton get_user_info(const char *username, const struct passwd **pwdp,
1583bbdb8a7SJamie Gritton login_cap_t **lcapp)
1593bbdb8a7SJamie Gritton {
1603bbdb8a7SJamie Gritton uid_t uid;
1613bbdb8a7SJamie Gritton const struct passwd *pwd;
1623bbdb8a7SJamie Gritton
1633bbdb8a7SJamie Gritton errno = 0;
1643bbdb8a7SJamie Gritton if (username) {
1653bbdb8a7SJamie Gritton pwd = getpwnam(username);
1663bbdb8a7SJamie Gritton if (pwd == NULL) {
1673bbdb8a7SJamie Gritton if (errno)
1683bbdb8a7SJamie Gritton err(1, "getpwnam: %s", username);
1693bbdb8a7SJamie Gritton else
1703bbdb8a7SJamie Gritton errx(1, "%s: no such user", username);
1713bbdb8a7SJamie Gritton }
1723bbdb8a7SJamie Gritton } else {
1733bbdb8a7SJamie Gritton uid = getuid();
1743bbdb8a7SJamie Gritton pwd = getpwuid(uid);
1753bbdb8a7SJamie Gritton if (pwd == NULL) {
1763bbdb8a7SJamie Gritton if (errno)
1773bbdb8a7SJamie Gritton err(1, "getpwuid: %d", uid);
1783bbdb8a7SJamie Gritton else
1793bbdb8a7SJamie Gritton errx(1, "unknown uid: %d", uid);
1803bbdb8a7SJamie Gritton }
1813bbdb8a7SJamie Gritton }
1823bbdb8a7SJamie Gritton *pwdp = pwd;
1833bbdb8a7SJamie Gritton *lcapp = login_getpwclass(pwd);
1843bbdb8a7SJamie Gritton if (*lcapp == NULL)
1853bbdb8a7SJamie Gritton err(1, "getpwclass: %s", pwd->pw_name);
1863bbdb8a7SJamie Gritton if (initgroups(pwd->pw_name, pwd->pw_gid) < 0)
1873bbdb8a7SJamie Gritton err(1, "initgroups: %s", pwd->pw_name);
1883bbdb8a7SJamie Gritton }
1893bbdb8a7SJamie Gritton
1903bbdb8a7SJamie Gritton static void
usage(void)191ebf5d9bcSMike Barcroft usage(void)
192ebf5d9bcSMike Barcroft {
193ebf5d9bcSMike Barcroft
19473d0971bSJamie Gritton fprintf(stderr, "%s\n",
195*d56f3b05SJamie Gritton "usage: jexec [-l] [-d working-directory] [-u username | -U username] jail\n"
196*d56f3b05SJamie Gritton " [command ...]");
197ebf5d9bcSMike Barcroft exit(1);
198ebf5d9bcSMike Barcroft }
199