MFC r285420:

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
This commit is contained in:
jamie 2015-07-30 04:53:53 +00:00
parent c3199153b4
commit 519cc2faa2
2 changed files with 101 additions and 41 deletions

View File

@ -25,7 +25,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd May 27, 2009 .Dd Jul 11, 2015
.Dt JEXEC 8 .Dt JEXEC 8
.Os .Os
.Sh NAME .Sh NAME
@ -33,8 +33,9 @@
.Nd "execute a command inside an existing jail" .Nd "execute a command inside an existing jail"
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl l
.Op Fl u Ar username | Fl U Ar username .Op Fl u Ar username | Fl U Ar username
.Ar jail command ... .Ar jail Op Ar command ...
.Sh DESCRIPTION .Sh DESCRIPTION
The The
.Nm .Nm
@ -43,9 +44,17 @@ utility executes
inside the inside the
.Ar jail .Ar jail
identified by its jid or name. identified by its jid or name.
If
.Ar command
is not specified then the user's shell is used.
.Pp .Pp
The following options are available: The following options are available:
.Bl -tag -width indent .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 .It Fl u Ar username
The user name from host environment as whom the The user name from host environment as whom the
.Ar command .Ar command

View File

@ -40,49 +40,37 @@
#include <jail.h> #include <jail.h>
#include <limits.h> #include <limits.h>
#include <login_cap.h> #include <login_cap.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <pwd.h>
#include <unistd.h> #include <unistd.h>
static void usage(void); extern char **environ;
#define GET_USER_INFO do { \ static void get_user_info(const char *username, const struct passwd **pwdp,
pwd = getpwnam(username); \ login_cap_t **lcapp);
if (pwd == NULL) { \ static void usage(void);
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)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int jid; int jid;
login_cap_t *lcap = NULL; login_cap_t *lcap = NULL;
struct passwd *pwd = NULL; int ch, clean, uflag, Uflag;
gid_t *groups = NULL; char *cleanenv;
int ch, ngroups, uflag, Uflag; const struct passwd *pwd = NULL;
long ngroups_max; const char *username, *shell, *term;
char *username;
ch = uflag = Uflag = 0; ch = clean = uflag = Uflag = 0;
username = NULL; 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) { switch (ch) {
case 'l':
clean = 1;
break;
case 'n': case 'n':
/* Specified name, now unused */ /* Specified name, now unused */
break; break;
@ -100,12 +88,15 @@ main(int argc, char *argv[])
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (argc < 2) if (argc < 1)
usage(); usage();
if (uflag && Uflag) if (uflag && Uflag)
usage(); usage();
if (uflag) if (uflag || (clean && !Uflag))
GET_USER_INFO; /* User info from the home environment */
get_user_info(username, &pwd, &lcap);
/* Attach to the jail */
jid = jail_getid(argv[0]); jid = jail_getid(argv[0]);
if (jid < 0) if (jid < 0)
errx(1, "%s", jail_errmsg); errx(1, "%s", jail_errmsg);
@ -113,28 +104,88 @@ main(int argc, char *argv[])
err(1, "jail_attach(%d)", jid); err(1, "jail_attach(%d)", jid);
if (chdir("/") == -1) if (chdir("/") == -1)
err(1, "chdir(): /"); err(1, "chdir(): /");
if (username != NULL) {
/* Set up user environment */
if (clean || username != NULL) {
if (Uflag) if (Uflag)
GET_USER_INFO; /* User info from the jail environment */
if (setgroups(ngroups, groups) != 0) get_user_info(username, &pwd, &lcap);
err(1, "setgroups"); 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) if (setgid(pwd->pw_gid) != 0)
err(1, "setgid"); err(1, "setgid");
if (setusercontext(lcap, pwd, pwd->pw_uid, if (setusercontext(lcap, pwd, pwd->pw_uid, username
LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0) ? LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN
: LOGIN_SETPATH | LOGIN_SETENV) != 0)
err(1, "setusercontext"); err(1, "setusercontext");
login_close(lcap); 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); 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 static void
usage(void) usage(void)
{ {
fprintf(stderr, "%s\n", fprintf(stderr, "%s\n",
"usage: jexec [-u username | -U username] jail command ..."); "usage: jexec [-l] [-u username | -U username] jail [command ...]");
exit(1); exit(1);
} }