From 3bbdb8a7553ae6c1139c76b26e2d84a8bcc8a996 Mon Sep 17 00:00:00 2001 From: Jamie Gritton Date: Sun, 12 Jul 2015 17:03:50 +0000 Subject: [PATCH] Run a shell in the jail when no command is specified. Add a new flag, -l, for a clean environment, same as jail(8) exec.clean. Change the GET_USER_INFO macro into a function. PR: 201300 Submitted by: Willem Jan Withagen MFC after: 3 days --- usr.sbin/jexec/jexec.8 | 13 ++++- usr.sbin/jexec/jexec.c | 129 ++++++++++++++++++++++++++++------------- 2 files changed, 101 insertions(+), 41 deletions(-) diff --git a/usr.sbin/jexec/jexec.8 b/usr.sbin/jexec/jexec.8 index a98af67b5017..19ed42d7be50 100644 --- a/usr.sbin/jexec/jexec.8 +++ b/usr.sbin/jexec/jexec.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 27, 2009 +.Dd Jul 11, 2015 .Dt JEXEC 8 .Os .Sh NAME @@ -33,8 +33,9 @@ .Nd "execute a command inside an existing jail" .Sh SYNOPSIS .Nm +.Op Fl l .Op Fl u Ar username | Fl U Ar username -.Ar jail command ... +.Ar jail Op Ar command ... .Sh DESCRIPTION The .Nm @@ -43,9 +44,17 @@ utility executes inside the .Ar jail identified by its jid or name. +If +.Ar command +is not specified then the user's shell is used. .Pp The following options are available: .Bl -tag -width indent +.It Fl l +Execute in a clean environment. +The environment is discarded except for +.Ev HOME , SHELL , TERM , USER , +and anything from the login class capability database for the user. .It Fl u Ar username The user name from host environment as whom the .Ar command diff --git a/usr.sbin/jexec/jexec.c b/usr.sbin/jexec/jexec.c index 8c15ebe98591..f8974dc4e916 100644 --- a/usr.sbin/jexec/jexec.c +++ b/usr.sbin/jexec/jexec.c @@ -40,49 +40,37 @@ #include #include #include +#include +#include #include #include #include -#include #include -static void usage(void); +extern char **environ; -#define GET_USER_INFO do { \ - pwd = getpwnam(username); \ - if (pwd == NULL) { \ - if (errno) \ - err(1, "getpwnam: %s", username); \ - else \ - errx(1, "%s: no such user", username); \ - } \ - lcap = login_getpwclass(pwd); \ - if (lcap == NULL) \ - err(1, "getpwclass: %s", username); \ - ngroups = ngroups_max; \ - if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0) \ - err(1, "getgrouplist: %s", username); \ -} while (0) +static void get_user_info(const char *username, const struct passwd **pwdp, + login_cap_t **lcapp); +static void usage(void); int main(int argc, char *argv[]) { int jid; login_cap_t *lcap = NULL; - struct passwd *pwd = NULL; - gid_t *groups = NULL; - int ch, ngroups, uflag, Uflag; - long ngroups_max; - char *username; + int ch, clean, uflag, Uflag; + char *cleanenv; + const struct passwd *pwd = NULL; + const char *username, *shell, *term; - ch = uflag = Uflag = 0; + ch = clean = uflag = Uflag = 0; username = NULL; - ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; - if ((groups = malloc(sizeof(gid_t) * ngroups_max)) == NULL) - err(1, "malloc"); - while ((ch = getopt(argc, argv, "nu:U:")) != -1) { + while ((ch = getopt(argc, argv, "lnu:U:")) != -1) { switch (ch) { + case 'l': + clean = 1; + break; case 'n': /* Specified name, now unused */ break; @@ -100,12 +88,15 @@ main(int argc, char *argv[]) } argc -= optind; argv += optind; - if (argc < 2) + if (argc < 1) usage(); if (uflag && Uflag) usage(); - if (uflag) - GET_USER_INFO; + if (uflag || (clean && !Uflag)) + /* User info from the home environment */ + get_user_info(username, &pwd, &lcap); + + /* Attach to the jail */ jid = jail_getid(argv[0]); if (jid < 0) errx(1, "%s", jail_errmsg); @@ -113,28 +104,88 @@ main(int argc, char *argv[]) err(1, "jail_attach(%d)", jid); if (chdir("/") == -1) err(1, "chdir(): /"); - if (username != NULL) { + + /* Set up user environment */ + if (clean || username != NULL) { if (Uflag) - GET_USER_INFO; - if (setgroups(ngroups, groups) != 0) - err(1, "setgroups"); + /* User info from the jail environment */ + get_user_info(username, &pwd, &lcap); + if (clean) { + term = getenv("TERM"); + cleanenv = NULL; + environ = &cleanenv; + setenv("PATH", "/bin:/usr/bin", 1); + if (term != NULL) + setenv("TERM", term, 1); + } if (setgid(pwd->pw_gid) != 0) err(1, "setgid"); - if (setusercontext(lcap, pwd, pwd->pw_uid, - LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0) + if (setusercontext(lcap, pwd, pwd->pw_uid, username + ? LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN + : LOGIN_SETPATH | LOGIN_SETENV) != 0) err(1, "setusercontext"); login_close(lcap); + setenv("USER", pwd->pw_name, 1); + setenv("HOME", pwd->pw_dir, 1); + setenv("SHELL", + *pwd->pw_shell ? pwd->pw_shell : _PATH_BSHELL, 1); + if (clean && chdir(pwd->pw_dir) < 0) + err(1, "chdir: %s", pwd->pw_dir); + endpwent(); + } + + /* Run the specified command, or the shell */ + if (argc > 1) { + if (execvp(argv[1], argv + 1) < 0) + err(1, "execvp: %s", argv[1]); + } else { + if (!(shell = getenv("SHELL"))) + shell = _PATH_BSHELL; + if (execlp(shell, shell, "-i", NULL) < 0) + err(1, "execlp: %s", shell); } - if (execvp(argv[1], argv + 1) == -1) - err(1, "execvp(): %s", argv[1]); exit(0); } +static void +get_user_info(const char *username, const struct passwd **pwdp, + login_cap_t **lcapp) +{ + uid_t uid; + const struct passwd *pwd; + + errno = 0; + if (username) { + pwd = getpwnam(username); + if (pwd == NULL) { + if (errno) + err(1, "getpwnam: %s", username); + else + errx(1, "%s: no such user", username); + } + } else { + uid = getuid(); + pwd = getpwuid(uid); + if (pwd == NULL) { + if (errno) + err(1, "getpwuid: %d", uid); + else + errx(1, "unknown uid: %d", uid); + } + } + *pwdp = pwd; + *lcapp = login_getpwclass(pwd); + if (*lcapp == NULL) + err(1, "getpwclass: %s", pwd->pw_name); + if (initgroups(pwd->pw_name, pwd->pw_gid) < 0) + err(1, "initgroups: %s", pwd->pw_name); +} + static void usage(void) { fprintf(stderr, "%s\n", - "usage: jexec [-u username | -U username] jail command ..."); + "usage: jexec [-l] [-u username | -U username] jail [command ...]"); exit(1); }