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