Add support for the arbitrary named jail parameters used by jail_set(2)
and jail_get(2). Jail(8) can now create jails using a "name=value" format instead of just specifying a limited set of fixed parameters; it can also modify parameters of existing jails. Jls(8) can display all parameters of jails, or a specified set of parameters. The available parameters are gathered from the kernel, and not hard-coded into these programs. Small patches on killall(1) and jexec(8) to support jail names with jail_get(2). Approved by: bz (mentor)
This commit is contained in:
parent
0304c73163
commit
73d0971bf2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=192896
@ -84,19 +84,11 @@ struct xprison {
|
|||||||
struct in6_addr pr_ip6[];
|
struct in6_addr pr_ip6[];
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
#define XPRISON_VERSION 3
|
#define XPRISON_VERSION 3
|
||||||
|
|
||||||
static const struct prison_state {
|
#define PRISON_STATE_INVALID 0
|
||||||
int pr_state;
|
#define PRISON_STATE_ALIVE 1
|
||||||
const char * state_name;
|
#define PRISON_STATE_DYING 2
|
||||||
} prison_states[] = {
|
|
||||||
#define PRISON_STATE_INVALID 0
|
|
||||||
{ PRISON_STATE_INVALID, "INVALID" },
|
|
||||||
#define PRISON_STATE_ALIVE 1
|
|
||||||
{ PRISON_STATE_ALIVE, "ALIVE" },
|
|
||||||
#define PRISON_STATE_DYING 2
|
|
||||||
{ PRISON_STATE_DYING, "DYING" },
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags for jail_set and jail_get.
|
* Flags for jail_set and jail_get.
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd November 9, 2007
|
.Dd May 27, 2009
|
||||||
.Os
|
.Os
|
||||||
.Dt KILLALL 1
|
.Dt KILLALL 1
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -34,7 +34,7 @@
|
|||||||
.Nm
|
.Nm
|
||||||
.Op Fl delmsvz
|
.Op Fl delmsvz
|
||||||
.Op Fl help
|
.Op Fl help
|
||||||
.Op Fl j Ar jid
|
.Op Fl j Ar jail
|
||||||
.Op Fl u Ar user
|
.Op Fl u Ar user
|
||||||
.Op Fl t Ar tty
|
.Op Fl t Ar tty
|
||||||
.Op Fl c Ar procname
|
.Op Fl c Ar procname
|
||||||
@ -91,9 +91,9 @@ The signal may be specified either as a name
|
|||||||
(with or without a leading
|
(with or without a leading
|
||||||
.Dq Li SIG ) ,
|
.Dq Li SIG ) ,
|
||||||
or numerically.
|
or numerically.
|
||||||
.It Fl j Ar jid
|
.It Fl j Ar jail
|
||||||
Kill processes in the jail specified by
|
Kill processes in the specified
|
||||||
.Ar jid .
|
.Ar jail .
|
||||||
.It Fl u Ar user
|
.It Fl u Ar user
|
||||||
Limit potentially matching processes to those belonging to
|
Limit potentially matching processes to those belonging to
|
||||||
the specified
|
the specified
|
||||||
|
@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/jail.h>
|
#include <sys/jail.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -51,7 +52,7 @@ static void __dead2
|
|||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jid]\n");
|
fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jail]\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
|
" [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
|
||||||
fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
|
fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
|
||||||
@ -100,6 +101,7 @@ nosig(char *name)
|
|||||||
int
|
int
|
||||||
main(int ac, char **av)
|
main(int ac, char **av)
|
||||||
{
|
{
|
||||||
|
struct iovec jparams[2];
|
||||||
struct kinfo_proc *procs = NULL, *newprocs;
|
struct kinfo_proc *procs = NULL, *newprocs;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
@ -159,12 +161,21 @@ main(int ac, char **av)
|
|||||||
}
|
}
|
||||||
jflag++;
|
jflag++;
|
||||||
if (*av == NULL)
|
if (*av == NULL)
|
||||||
errx(1, "must specify jid");
|
errx(1, "must specify jail");
|
||||||
jid = strtol(*av, &ep, 10);
|
jid = strtoul(*av, &ep, 10);
|
||||||
if (!*av || *ep)
|
if (!**av || *ep) {
|
||||||
errx(1, "illegal jid: %s", *av);
|
*(const void **)&jparams[0].iov_base =
|
||||||
|
"name";
|
||||||
|
jparams[0].iov_len = sizeof("name");
|
||||||
|
jparams[1].iov_base = *av;
|
||||||
|
jparams[1].iov_len = strlen(*av) + 1;
|
||||||
|
jid = jail_get(jparams, 2, 0);
|
||||||
|
if (jid < 0)
|
||||||
|
errx(1, "unknown jail: %s",
|
||||||
|
*av);
|
||||||
|
}
|
||||||
if (jail_attach(jid) == -1)
|
if (jail_attach(jid) == -1)
|
||||||
err(1, "jail_attach(): %d", jid);
|
err(1, "jail_attach(%d)", jid);
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
++*av;
|
++*av;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2000, 2003 Robert N. M. Watson
|
.\" Copyright (c) 2000, 2003 Robert N. M. Watson
|
||||||
|
.\" Copyright (c) 2008 James Gritton
|
||||||
.\" All rights reserved.
|
.\" All rights reserved.
|
||||||
.\"
|
.\"
|
||||||
.\" Redistribution and use in source and binary forms, with or without
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
@ -33,49 +34,67 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd January 24, 2009
|
.Dd May 27, 2009
|
||||||
.Dt JAIL 8
|
.Dt JAIL 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm jail
|
.Nm jail
|
||||||
.Nd "imprison process and its descendants"
|
.Nd "create or modify a system jail"
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
|
.Op Fl dhi
|
||||||
|
.Op Fl J Ar jid_file
|
||||||
|
.Op Fl l u Ar username | Fl U Ar username
|
||||||
|
.Op Fl c | m
|
||||||
|
.Op Ar parameter=value ...
|
||||||
|
.Br
|
||||||
|
.Nm
|
||||||
.Op Fl hi
|
.Op Fl hi
|
||||||
.Op Fl n Ar jailname
|
.Op Fl n Ar jailname
|
||||||
.Op Fl J Ar jid_file
|
.Op Fl J Ar jid_file
|
||||||
.Op Fl s Ar securelevel
|
.Op Fl s Ar securelevel
|
||||||
.Op Fl l u Ar username | Fl U Ar username
|
.Op Fl l u Ar username | Fl U Ar username
|
||||||
.Ar path hostname [ip[,..]] command ...
|
.Op Ar path hostname [ip[,..]] command ...
|
||||||
|
.Br
|
||||||
|
.Nm
|
||||||
|
.Op Fl r Ar jail
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
utility imprisons a process and all future descendants.
|
utility creates a new jail or modifies an existing jail, optionally
|
||||||
|
imprisoning the current process (and future descendants) inside it.
|
||||||
.Pp
|
.Pp
|
||||||
The options are as follows:
|
The options are as follows:
|
||||||
.Bl -tag -width ".Fl u Ar username"
|
.Bl -tag -width indent
|
||||||
|
.It Fl d
|
||||||
|
Allow making changes to a
|
||||||
|
.Va
|
||||||
|
dying jail.
|
||||||
.It Fl h
|
.It Fl h
|
||||||
Resolve
|
Resolve the
|
||||||
.Va hostname
|
.Va host.hostname
|
||||||
|
parameter (or
|
||||||
|
.Va hostname )
|
||||||
and add all IP addresses returned by the resolver
|
and add all IP addresses returned by the resolver
|
||||||
to the list of
|
to the list of
|
||||||
.Va ip-addresses
|
.Va ip
|
||||||
for this prison.
|
addresses for this prison.
|
||||||
This may affect default address selection for outgoing IPv4 connections
|
This may affect default address selection for outgoing IPv4 connections
|
||||||
of prisons.
|
of prisons.
|
||||||
The address first returned by the resolver for each address family
|
The address first returned by the resolver for each address family
|
||||||
will be used as primary address.
|
will be used as primary address.
|
||||||
See
|
See the
|
||||||
.Va ip-addresses
|
.Va ip4.addr
|
||||||
further down for details.
|
and
|
||||||
|
.Va ip6.addr
|
||||||
|
parameters further down for details.
|
||||||
.It Fl i
|
.It Fl i
|
||||||
Output the jail identifier of the newly created jail.
|
Output the jail identifier of the newly created jail.
|
||||||
.It Fl n Ar jailname
|
.It Fl n Ar jailname
|
||||||
Assign and administrative name to the jail that can be used for management
|
Set the jail's name.
|
||||||
or auditing purposes.
|
This is deprecated and is equivalent to setting the
|
||||||
The system will
|
.Va name
|
||||||
.Sy not enforce
|
parameter.
|
||||||
the name to be unique.
|
|
||||||
.It Fl J Ar jid_file
|
.It Fl J Ar jid_file
|
||||||
Write a
|
Write a
|
||||||
.Ar jid_file
|
.Ar jid_file
|
||||||
@ -98,9 +117,12 @@ is imported from the current environment.
|
|||||||
The environment variables from the login class capability database for the
|
The environment variables from the login class capability database for the
|
||||||
target login are also set.
|
target login are also set.
|
||||||
.It Fl s Ar securelevel
|
.It Fl s Ar securelevel
|
||||||
Sets the
|
Set the
|
||||||
.Va kern.securelevel
|
.Va kern.securelevel
|
||||||
sysctl variable to the specified value inside the newly created jail.
|
MIB entry to the specified value inside the newly created jail.
|
||||||
|
This is deprecated and is equivalent to setting the
|
||||||
|
.Va securelevel
|
||||||
|
parameter.
|
||||||
.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
|
||||||
@ -109,20 +131,241 @@ should run.
|
|||||||
The user name from jailed environment as whom the
|
The user name from jailed environment as whom the
|
||||||
.Ar command
|
.Ar command
|
||||||
should run.
|
should run.
|
||||||
.It Ar path
|
.It Fl c
|
||||||
|
Create a new jail.
|
||||||
|
The
|
||||||
|
.Va jid
|
||||||
|
and
|
||||||
|
.Va name
|
||||||
|
parameters (if specified) must not refer to an existing jail.
|
||||||
|
.It Fl m
|
||||||
|
Modify an existing jail.
|
||||||
|
One of the
|
||||||
|
.Va jid
|
||||||
|
or
|
||||||
|
.Va name
|
||||||
|
parameters must exist and refer to an existing jail.
|
||||||
|
.It Fl cm
|
||||||
|
Create a jail if it does not exist, or modify a jail if it does exist.
|
||||||
|
.It Fl r
|
||||||
|
Remove the
|
||||||
|
.Ar jail
|
||||||
|
specified by jid or name.
|
||||||
|
All jailed processes are killed, and all children of this jail are also
|
||||||
|
removed.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
At least one of the
|
||||||
|
.Fl c ,
|
||||||
|
.Fl m
|
||||||
|
or
|
||||||
|
.Fl r
|
||||||
|
options must be specified.
|
||||||
|
.Pp
|
||||||
|
.Ar Parameters
|
||||||
|
are listed in
|
||||||
|
.Dq name=value
|
||||||
|
form, following the options.
|
||||||
|
Some parameters are boolean, and do not have a value but are set by the
|
||||||
|
name alone with or without a
|
||||||
|
.Dq no
|
||||||
|
prefix, e.g.
|
||||||
|
.Va persist
|
||||||
|
or
|
||||||
|
.Va nopersist .
|
||||||
|
Any parameters not set will be given default values, often based on the
|
||||||
|
current environment.
|
||||||
|
.Pp
|
||||||
|
The pseudo-parameter
|
||||||
|
.Va command
|
||||||
|
specifies that the current process should enter the new (or modified) jail,
|
||||||
|
and run the specified command.
|
||||||
|
It must be the last parameter specified, because it includes not only
|
||||||
|
the value following the
|
||||||
|
.Sq =
|
||||||
|
sign, but also passes the rest of the arguments to the command.
|
||||||
|
.Pp
|
||||||
|
Instead of supplying named
|
||||||
|
.Ar parameters ,
|
||||||
|
four fixed parameters may be supplied in order on the command line:
|
||||||
|
.Ar path ,
|
||||||
|
.Ar hostname ,
|
||||||
|
.Ar ip ,
|
||||||
|
and
|
||||||
|
.Ar command .
|
||||||
|
As the
|
||||||
|
.Va jid
|
||||||
|
and
|
||||||
|
.Va name
|
||||||
|
parameters aren't in this list, this mode will always create a new jail, and
|
||||||
|
the
|
||||||
|
.Fl c
|
||||||
|
and
|
||||||
|
.Fl o
|
||||||
|
options don't apply (and must not exist).
|
||||||
|
.Pp
|
||||||
|
Jails have a set a core parameters, and modules can add their own jail
|
||||||
|
parameters.
|
||||||
|
The current set of available parameters can be retrieved via
|
||||||
|
.Dq Nm sysctl Fl d Va security.jail.param .
|
||||||
|
The core parameters are:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Va jid
|
||||||
|
The jail identifier.
|
||||||
|
This will be assigned automatically to a new jail (or can be explicitly
|
||||||
|
set), and can be used to identify the jail for later modification, or
|
||||||
|
for such commands as
|
||||||
|
.Xr jls 8
|
||||||
|
or
|
||||||
|
.Xr jexec 8 .
|
||||||
|
.It Va name
|
||||||
|
The jail name.
|
||||||
|
This is an arbitrary string that identifies a jail (except it may not
|
||||||
|
contain a
|
||||||
|
.Sq \&. ) .
|
||||||
|
Like the
|
||||||
|
.Va jid ,
|
||||||
|
it can be passed to later
|
||||||
|
.Nm
|
||||||
|
commands, or to
|
||||||
|
.Xr jls 8
|
||||||
|
or
|
||||||
|
.Xr jexec 8 .
|
||||||
|
If no
|
||||||
|
.Va name
|
||||||
|
is supplied, a default is assumed that is the same as the
|
||||||
|
.Va jid .
|
||||||
|
.It Va path
|
||||||
Directory which is to be the root of the prison.
|
Directory which is to be the root of the prison.
|
||||||
.It Ar hostname
|
The
|
||||||
Hostname of the prison.
|
.Va command
|
||||||
.It Ar ip-addresses
|
(if any) is run from this directory, as are commands from
|
||||||
None, one or more IPv4 and IPv6 addresses assigned to the prison.
|
.Xr jexec 8 .
|
||||||
The first address of each address family that was assigned to the jail will
|
.It Va ip4.addr
|
||||||
be used as the source address in case source address selection on unbound
|
A comma-separated list of IPv4 addresses assigned to the prison.
|
||||||
sockets cannot find a better match.
|
If this is set, the jail is restricted to using only these address.
|
||||||
|
Any attempts to use other addresses fail, and attempts to use wildcard
|
||||||
|
addresses silently use the jailed address instead.
|
||||||
|
For IPv4 the first address given will be kept used as the source address
|
||||||
|
in case source address selection on unbound sockets cannot find a better
|
||||||
|
match.
|
||||||
It is only possible to start multiple jails with the same IP address,
|
It is only possible to start multiple jails with the same IP address,
|
||||||
if none of the jails has more than this single overlapping IP address
|
if none of the jails has more than this single overlapping IP address
|
||||||
assigned to itself for the address family in question.
|
assigned to itself.
|
||||||
.It Ar command
|
.Pp
|
||||||
Pathname of the program which is to be executed.
|
A list of zero elements (an empty string) will stop the jail from using IPv4
|
||||||
|
entirely; setting the boolean parameter
|
||||||
|
.Ar noip4
|
||||||
|
will not restrict the jail at all.
|
||||||
|
.It Va ip6.addr
|
||||||
|
A list of IPv6 addresses assigned to the prison, the counterpart to
|
||||||
|
.Ar ip4.addr
|
||||||
|
above.
|
||||||
|
.It Va host.hostname
|
||||||
|
Hostname of the prison.
|
||||||
|
If not specified, a jail will use the system hostname.
|
||||||
|
.It Va securelevel
|
||||||
|
The value of the jail's
|
||||||
|
.Va kern.securelevel
|
||||||
|
sysctl.
|
||||||
|
A jail never has a lower securelevel than the default system, but by
|
||||||
|
setting this parameter it may have a higher one.
|
||||||
|
If the system securelevel is changed, any jail securelevels will be at
|
||||||
|
least as secure.
|
||||||
|
.It Va enforce_statfs
|
||||||
|
This determines which information processes in a jail are able to get
|
||||||
|
about mount points.
|
||||||
|
It affects the behaviour of the following syscalls:
|
||||||
|
.Xr statfs 2 ,
|
||||||
|
.Xr fstatfs 2 ,
|
||||||
|
.Xr getfsstat 2
|
||||||
|
and
|
||||||
|
.Xr fhstatfs 2
|
||||||
|
(as well as similar compatibility syscalls).
|
||||||
|
When set to 0, all mount points are available without any restrictions.
|
||||||
|
When set to 1, only mount points below the jail's chroot directory are
|
||||||
|
visible.
|
||||||
|
In addition to that, the path to the jail's chroot directory is removed
|
||||||
|
from the front of their pathnames.
|
||||||
|
When set to 2 (default), above syscalls can operate only on a mount-point
|
||||||
|
where the jail's chroot directory is located.
|
||||||
|
.It Va persist
|
||||||
|
Setting this boolean parameter allows a jail to exist without any
|
||||||
|
processes.
|
||||||
|
Normally, a jail is destroyed as its last process exits.
|
||||||
|
A new jail must have either the
|
||||||
|
.Va persist
|
||||||
|
parameter or
|
||||||
|
.Va command
|
||||||
|
pseudo-parameter set.
|
||||||
|
.It Va cpuset
|
||||||
|
The ID of the cpuset associated with this jail (read-only).
|
||||||
|
.It Va dying
|
||||||
|
This is true if the jail is in the process of shutting down (read-only).
|
||||||
|
.It Va parent
|
||||||
|
The
|
||||||
|
.Va jid
|
||||||
|
of the parent of this jail, or zero if this is a top-level jail
|
||||||
|
(read-only).
|
||||||
|
.It Va allow.*
|
||||||
|
Some restrictions of the jail environment may be set on a per-jail
|
||||||
|
basis.
|
||||||
|
With the exception of
|
||||||
|
.Va allow.set_hostname ,
|
||||||
|
these boolean parameters are off by default.
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Va allow.set_hostname
|
||||||
|
The jail's hostname may be changed via
|
||||||
|
.Xr hostname 1
|
||||||
|
or
|
||||||
|
.Xr sethostname 3 .
|
||||||
|
.It Va allow.sysvipc
|
||||||
|
A process within the jail has access to System V IPC primitives.
|
||||||
|
In the current jail implementation, System V primitives share a single
|
||||||
|
namespace across the host and jail environments, meaning that processes
|
||||||
|
within a jail would be able to communicate with (and potentially interfere
|
||||||
|
with) processes outside of the jail, and in other jails.
|
||||||
|
.It Va allow.raw_sockets
|
||||||
|
The prison root is allowed to create raw sockets.
|
||||||
|
Setting this parameter allows utilities like
|
||||||
|
.Xr ping 8
|
||||||
|
and
|
||||||
|
.Xr traceroute 8
|
||||||
|
to operate inside the prison.
|
||||||
|
If this is set, the source IP addresses are enforced to comply
|
||||||
|
with the IP address bound to the jail, regardless of whether or not
|
||||||
|
the
|
||||||
|
.Dv IP_HDRINCL
|
||||||
|
flag has been set on the socket.
|
||||||
|
Since raw sockets can be used to configure and interact with various
|
||||||
|
network subsystems, extra caution should be used where privileged access
|
||||||
|
to jails is given out to untrusted parties.
|
||||||
|
.It Va allow.chflags
|
||||||
|
Normally, priveleged users inside a jail are treated as unprivileged by
|
||||||
|
.Xr chflags 2 .
|
||||||
|
When this parameter is set, such users are treated as privileged, and
|
||||||
|
may manipulate system file flags subject to the usual constraints on
|
||||||
|
.Va kern.securelevel .
|
||||||
|
.It Va allow.mount
|
||||||
|
privileged users inside the jail will be able to mount and unmount file
|
||||||
|
system types marked as jail-friendly.
|
||||||
|
The
|
||||||
|
.Xr lsvfs 1
|
||||||
|
command can be used to find file system types available for mount from
|
||||||
|
within a jail.
|
||||||
|
.It Va allow.quotas
|
||||||
|
The prison root may administer quotas on the jail's filesystem(s).
|
||||||
|
This includes filesystems that the jail may share with other jails or
|
||||||
|
with non-jailed parts of the system.
|
||||||
|
.It Va allow.socket_af
|
||||||
|
Sockets within a jail are normally restricted to IPv4, IPv6, local
|
||||||
|
(UNIX), and route. This allows access to other protocol stacks that
|
||||||
|
have not had jail functionality added to them.
|
||||||
|
.It Va allow.jails
|
||||||
|
The prison root may create child jails under this jail. See the
|
||||||
|
.Va "Hierarchical Jails"
|
||||||
|
section for more information.
|
||||||
|
.El
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Jails are typically set up using one of two philosophies: either to
|
Jails are typically set up using one of two philosophies: either to
|
||||||
@ -142,10 +385,6 @@ process.
|
|||||||
This manual page documents the configuration steps necessary to support
|
This manual page documents the configuration steps necessary to support
|
||||||
either of these steps, although the configuration steps may be
|
either of these steps, although the configuration steps may be
|
||||||
refined based on local requirements.
|
refined based on local requirements.
|
||||||
.Pp
|
|
||||||
Please see the
|
|
||||||
.Xr jail 2
|
|
||||||
man page for further details.
|
|
||||||
.Sh EXAMPLES
|
.Sh EXAMPLES
|
||||||
.Ss "Setting up a Jail Directory Tree"
|
.Ss "Setting up a Jail Directory Tree"
|
||||||
To set up a jail directory tree containing an entire
|
To set up a jail directory tree containing an entire
|
||||||
@ -289,7 +528,10 @@ or for running a virtual server.
|
|||||||
.Pp
|
.Pp
|
||||||
Start a shell in the jail:
|
Start a shell in the jail:
|
||||||
.Pp
|
.Pp
|
||||||
.Dl "jail /data/jail/192.0.2.100 testhostname 192.0.2.100 /bin/sh"
|
.Bd -literal -offset indent
|
||||||
|
jail path=/data/jail/192.0.2.100 host.hostname=testhostname \\
|
||||||
|
ip4.addr=192.0.2.100 command=/bin/sh
|
||||||
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Assuming no errors, you will end up with a shell prompt within the jail.
|
Assuming no errors, you will end up with a shell prompt within the jail.
|
||||||
You can now run
|
You can now run
|
||||||
@ -359,20 +601,11 @@ To do this, first bring up the
|
|||||||
virtual host interface, and then start the jail's
|
virtual host interface, and then start the jail's
|
||||||
.Pa /etc/rc
|
.Pa /etc/rc
|
||||||
script from within the jail.
|
script from within the jail.
|
||||||
.Pp
|
|
||||||
NOTE: If you plan to allow untrusted users to have root access inside the
|
|
||||||
jail, you may wish to consider setting the
|
|
||||||
.Va security.jail.set_hostname_allowed
|
|
||||||
sysctl variable to 0.
|
|
||||||
Please see the management discussion later in this document as to why this
|
|
||||||
may be a good idea.
|
|
||||||
If you do decide to set this variable,
|
|
||||||
it must be set before starting any jails, and once each boot.
|
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
ifconfig ed0 inet alias 192.0.2.100/32
|
ifconfig ed0 inet alias 192.0.2.100/32
|
||||||
mount -t procfs proc /data/jail/192.0.2.100/proc
|
mount -t procfs proc /data/jail/192.0.2.100/proc
|
||||||
jail /data/jail/192.0.2.100 testhostname 192.0.2.100 \\
|
jail path=/data/jail/192.0.2.100 host.hostname=testhostname \\
|
||||||
/bin/sh /etc/rc
|
ip4=addr.192.0.2.100 command=/bin/sh /etc/rc
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
A few warnings will be produced, because most
|
A few warnings will be produced, because most
|
||||||
@ -442,10 +675,15 @@ To kill processes from outside the jail, use the
|
|||||||
utility in conjunction with the one of the
|
utility in conjunction with the one of the
|
||||||
.Xr kill 1
|
.Xr kill 1
|
||||||
commands above.
|
commands above.
|
||||||
|
You may also remove the jail with
|
||||||
|
.Nm
|
||||||
|
.Ar -r ,
|
||||||
|
which will killall the jail's processes with
|
||||||
|
.Dv SIGKILL .
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Pa /proc/ Ns Ar pid Ns Pa /status
|
.Pa /proc/ Ns Ar pid Ns Pa /status
|
||||||
file contains, as its last field, the hostname of the jail in which the
|
file contains, as its last field, the name of the jail in which the
|
||||||
process runs, or
|
process runs, or
|
||||||
.Dq Li -
|
.Dq Li -
|
||||||
to indicate that the process is not running within a jail.
|
to indicate that the process is not running within a jail.
|
||||||
@ -454,20 +692,6 @@ The
|
|||||||
command also shows a
|
command also shows a
|
||||||
.Ql J
|
.Ql J
|
||||||
flag for processes in a jail.
|
flag for processes in a jail.
|
||||||
However, the hostname for a jail may be, by
|
|
||||||
default, modified from within the jail, so the
|
|
||||||
.Pa /proc
|
|
||||||
status entry is unreliable by default.
|
|
||||||
To disable the setting of the hostname
|
|
||||||
from within a jail, set the
|
|
||||||
.Va security.jail.set_hostname_allowed
|
|
||||||
sysctl variable in the host environment to 0, which will affect all jails.
|
|
||||||
You can have this sysctl set on each boot using
|
|
||||||
.Xr sysctl.conf 5 .
|
|
||||||
Just add the following line to
|
|
||||||
.Pa /etc/sysctl.conf :
|
|
||||||
.Pp
|
|
||||||
.Dl security.jail.set_hostname_allowed=0
|
|
||||||
.Pp
|
.Pp
|
||||||
You can also list/kill processes based on their jail ID.
|
You can also list/kill processes based on their jail ID.
|
||||||
To show processes and their jail ID, use the following command:
|
To show processes and their jail ID, use the following command:
|
||||||
@ -488,12 +712,9 @@ It is not possible to
|
|||||||
or
|
or
|
||||||
.Xr umount 8
|
.Xr umount 8
|
||||||
any file system inside a jail unless the file system is marked
|
any file system inside a jail unless the file system is marked
|
||||||
jail-friendly.
|
jail-friendly and the jail's
|
||||||
See
|
.Va allow.mount
|
||||||
.Va security.jail.mount_allowed
|
parameter is set.
|
||||||
in the
|
|
||||||
.Va "Sysctl MIB Entries"
|
|
||||||
section.
|
|
||||||
.Pp
|
.Pp
|
||||||
Multiple jails sharing the same file system can influence each other.
|
Multiple jails sharing the same file system can influence each other.
|
||||||
For example a user in one jail can fill the file system also
|
For example a user in one jail can fill the file system also
|
||||||
@ -506,132 +727,77 @@ This means the same user ID in two jails share the same file
|
|||||||
system quota.
|
system quota.
|
||||||
One would need to use one file system per jail to make this working.
|
One would need to use one file system per jail to make this working.
|
||||||
.Ss "Sysctl MIB Entries"
|
.Ss "Sysctl MIB Entries"
|
||||||
Certain aspects of the jail containments environment may be modified from
|
The read-only entry
|
||||||
the host environment using
|
|
||||||
.Xr sysctl 8
|
|
||||||
MIB variables.
|
|
||||||
Currently, these variables affect all jails on the system, although in
|
|
||||||
the future this functionality may be finer grained.
|
|
||||||
.Bl -tag -width XXX
|
|
||||||
.It Va security.jail.allow_raw_sockets
|
|
||||||
This MIB entry determines whether or not prison root is allowed to
|
|
||||||
create raw sockets.
|
|
||||||
Setting this MIB to 1 allows utilities like
|
|
||||||
.Xr ping 8
|
|
||||||
and
|
|
||||||
.Xr traceroute 8
|
|
||||||
to operate inside the prison.
|
|
||||||
If this MIB
|
|
||||||
is set, the source IP addresses are enforced to comply
|
|
||||||
with the IP address bound to the jail, regardless of whether or not
|
|
||||||
the
|
|
||||||
.Dv IP_HDRINCL
|
|
||||||
flag has been set on the socket.
|
|
||||||
Since raw sockets can be used to configure
|
|
||||||
and interact with various network subsystems, extra caution should be used
|
|
||||||
where privileged access to jails is given out to untrusted parties.
|
|
||||||
As such,
|
|
||||||
by default this option is disabled.
|
|
||||||
.It Va security.jail.enforce_statfs
|
|
||||||
This MIB entry determines which information processes in a jail are
|
|
||||||
able to get about mount-points.
|
|
||||||
It affects the behaviour of the following syscalls:
|
|
||||||
.Xr statfs 2 ,
|
|
||||||
.Xr fstatfs 2 ,
|
|
||||||
.Xr getfsstat 2
|
|
||||||
and
|
|
||||||
.Xr fhstatfs 2
|
|
||||||
(as well as similar compatibility syscalls).
|
|
||||||
When set to 0, all mount-points are available without any restrictions.
|
|
||||||
When set to 1, only mount-points below the jail's chroot directory are
|
|
||||||
visible.
|
|
||||||
In addition to that, the path to the jail's chroot directory is removed
|
|
||||||
from the front of their pathnames.
|
|
||||||
When set to 2 (default), above syscalls can operate only on a mount-point
|
|
||||||
where the jail's chroot directory is located.
|
|
||||||
.It Va security.jail.set_hostname_allowed
|
|
||||||
This MIB entry determines whether or not processes within a jail are
|
|
||||||
allowed to change their hostname via
|
|
||||||
.Xr hostname 1
|
|
||||||
or
|
|
||||||
.Xr sethostname 3 .
|
|
||||||
In the current jail implementation, the ability to set the hostname from
|
|
||||||
within the jail can impact management tools relying on the accuracy of jail
|
|
||||||
information in
|
|
||||||
.Pa /proc .
|
|
||||||
As such, this should be disabled in environments where privileged access to
|
|
||||||
jails is given out to untrusted parties.
|
|
||||||
.It Va security.jail.socket_unixiproute_only
|
|
||||||
The jail functionality binds an IPv4 address to each jail, and limits
|
|
||||||
access to other network addresses in the IPv4 space that may be available
|
|
||||||
in the host environment.
|
|
||||||
However, jail is not currently able to limit access to other network
|
|
||||||
protocol stacks that have not had jail functionality added to them.
|
|
||||||
As such, by default, processes within jails may only access protocols
|
|
||||||
in the following domains:
|
|
||||||
.Dv PF_LOCAL , PF_INET ,
|
|
||||||
and
|
|
||||||
.Dv PF_ROUTE ,
|
|
||||||
permitting them access to
|
|
||||||
.Ux
|
|
||||||
domain sockets,
|
|
||||||
IPv4 addresses, and routing sockets.
|
|
||||||
To enable access to other domains, this MIB variable may be set to
|
|
||||||
0.
|
|
||||||
.It Va security.jail.sysvipc_allowed
|
|
||||||
This MIB entry determines whether or not processes within a jail have access
|
|
||||||
to System V IPC primitives.
|
|
||||||
In the current jail implementation, System V primitives share a single
|
|
||||||
namespace across the host and jail environments, meaning that processes
|
|
||||||
within a jail would be able to communicate with (and potentially interfere
|
|
||||||
with) processes outside of the jail, and in other jails.
|
|
||||||
As such, this functionality is disabled by default, but can be enabled
|
|
||||||
by setting this MIB entry to 1.
|
|
||||||
.It Va security.jail.chflags_allowed
|
|
||||||
This MIB entry determines how a privileged user inside a jail will be
|
|
||||||
treated by
|
|
||||||
.Xr chflags 2 .
|
|
||||||
If zero, such users are treated as unprivileged, and are unable to set
|
|
||||||
or clear system file flags; if non-zero, such users are treated as
|
|
||||||
privileged, and may manipulate system file flags subject to the usual
|
|
||||||
constraints on
|
|
||||||
.Va kern.securelevel .
|
|
||||||
.It Va security.jail.mount_allowed
|
|
||||||
This MIB entry determines if a privileged user inside a jail will be
|
|
||||||
able to mount and unmount file system types marked as jail-friendly.
|
|
||||||
The
|
|
||||||
.Xr lsvfs 1
|
|
||||||
command can be used to find file system types available for mount from within
|
|
||||||
a jail.
|
|
||||||
This functionality is disabled by default, but can be enabled by setting this
|
|
||||||
MIB entry to 1.
|
|
||||||
.It Va security.jail.jail_max_af_ips
|
|
||||||
This MIB entry determines how may address per address family a prison
|
|
||||||
may have. The default is 255.
|
|
||||||
.El
|
|
||||||
.Pp
|
|
||||||
The read-only sysctl variable
|
|
||||||
.Va security.jail.jailed
|
.Va security.jail.jailed
|
||||||
can be used to determine if a process is running inside a jail (value
|
can be used to determine if a process is running inside a jail (value
|
||||||
is one) or not (value is zero).
|
is one) or not (value is zero).
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The variable
|
||||||
.Va security.jail.list
|
.Va security.jail.max_af_ips
|
||||||
MIB entry is read-only and it returns an array of
|
determines how may address per address family a prison may have.
|
||||||
.Vt "struct xprison"
|
The default is 255.
|
||||||
defined in
|
|
||||||
.In sys/jail.h .
|
|
||||||
It is recommended to use the
|
|
||||||
.Xr jls 8
|
|
||||||
utility to see current active list of jails.
|
|
||||||
.Pp
|
.Pp
|
||||||
There are currently two MIB related variables that have per-jail settings.
|
There are currently two MIB variables that have per-jail settings.
|
||||||
Changes to these variables by a jailed process do not effect the host
|
Changes to these variables by a jailed process do not effect the host
|
||||||
environment, only the jail environment.
|
environment, only the jail environment.
|
||||||
The variables are
|
The variables are
|
||||||
.Va kern.securelevel
|
.Va kern.securelevel
|
||||||
and
|
and
|
||||||
.Va kern.hostname .
|
.Va kern.hostname .
|
||||||
|
.Ss "Hierarchical Jails"
|
||||||
|
By setting a jail's
|
||||||
|
.Va allow.jails
|
||||||
|
parameter, processes within a jail may be able to create jails of their own.
|
||||||
|
These child jails are kept in a hierarchy, with jails only able to see and/or
|
||||||
|
modify the jails they created (or those jails' children).
|
||||||
|
Each jail has a read-only
|
||||||
|
.Va parent
|
||||||
|
parameter, containing the
|
||||||
|
.Va jid
|
||||||
|
of the jail that created it; a
|
||||||
|
.Va jid
|
||||||
|
of 0 indicates the jail is a child of the current jail (or is a top-level
|
||||||
|
jail if the current process isn't jailed).
|
||||||
|
.Pp
|
||||||
|
Jailed processes are not allowed to confer greater permissions than they
|
||||||
|
themselves are given, e.g. if a jail is created with
|
||||||
|
.Va allow.nomount ,
|
||||||
|
it is not able to create a jail with
|
||||||
|
.Va allow.mount
|
||||||
|
set.
|
||||||
|
Similarly, such restrictions as
|
||||||
|
.Va ip4.addr
|
||||||
|
and
|
||||||
|
.Va securelevel
|
||||||
|
may not be bypassed in child jails.
|
||||||
|
.Pp
|
||||||
|
A child jail may in turn create its own child jails if its own
|
||||||
|
.Va allow.jails
|
||||||
|
parameter is set (remember it is off by default).
|
||||||
|
These jails are visible to and can be modified by their parent and all
|
||||||
|
ancestors.
|
||||||
|
.Pp
|
||||||
|
Jail names reflect this hierarchy, with a full name being an MIB-type string
|
||||||
|
separated by dots.
|
||||||
|
For example, if a base system process creates a jail
|
||||||
|
.Dq foo ,
|
||||||
|
and a process under that jail creates another jail
|
||||||
|
.Dq bar ,
|
||||||
|
then the second jail will be seen as
|
||||||
|
.Dq foo.bar
|
||||||
|
in the base system (though it is only seen as
|
||||||
|
.Dq bar
|
||||||
|
to any processes inside jail
|
||||||
|
.Dq foo ) .
|
||||||
|
Jids on the other hand exist in a single space, and each jail must have a
|
||||||
|
unique jid.
|
||||||
|
.Pp
|
||||||
|
Like the names, a child jail's
|
||||||
|
.Va path
|
||||||
|
is relative to its creator's own
|
||||||
|
.Va path .
|
||||||
|
This is by virtue of the child jail being created in the chrooted
|
||||||
|
environment of the first jail.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr killall 1 ,
|
.Xr killall 1 ,
|
||||||
.Xr lsvfs 1 ,
|
.Xr lsvfs 1 ,
|
||||||
@ -641,7 +807,7 @@ and
|
|||||||
.Xr ps 1 ,
|
.Xr ps 1 ,
|
||||||
.Xr quota 1 ,
|
.Xr quota 1 ,
|
||||||
.Xr chroot 2 ,
|
.Xr chroot 2 ,
|
||||||
.Xr jail 2 ,
|
.Xr jail_set 2 ,
|
||||||
.Xr jail_attach 2 ,
|
.Xr jail_attach 2 ,
|
||||||
.Xr procfs 5 ,
|
.Xr procfs 5 ,
|
||||||
.Xr rc.conf 5 ,
|
.Xr rc.conf 5 ,
|
||||||
@ -665,6 +831,8 @@ The
|
|||||||
.Nm
|
.Nm
|
||||||
utility appeared in
|
utility appeared in
|
||||||
.Fx 4.0 .
|
.Fx 4.0 .
|
||||||
|
Hierarchical/extensible jails were introduced in
|
||||||
|
.Fx 8.0 .
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
.An -nosplit
|
.An -nosplit
|
||||||
The jail feature was written by
|
The jail feature was written by
|
||||||
@ -683,6 +851,9 @@ added multi-IP jail support for IPv4 and IPv6 based on a patch
|
|||||||
originally done by
|
originally done by
|
||||||
.An Pawel Jakub Dawidek
|
.An Pawel Jakub Dawidek
|
||||||
for IPv4.
|
for IPv4.
|
||||||
|
.Pp
|
||||||
|
.An James Gritton
|
||||||
|
added the extensible jail parameters and hierchical jails.
|
||||||
.Sh BUGS
|
.Sh BUGS
|
||||||
Jail currently lacks the ability to allow access to
|
Jail currently lacks the ability to allow access to
|
||||||
specific jail information via
|
specific jail information via
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1999 Poul-Henning Kamp.
|
* Copyright (c) 1999 Poul-Henning Kamp.
|
||||||
|
* Copyright (c) 2009 James Gritton
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -29,50 +30,53 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/jail.h>
|
#include <sys/jail.h>
|
||||||
#include <sys/queue.h>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <login_cap.h>
|
#include <login_cap.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static void usage(void);
|
#define SJPARAM "security.jail.param"
|
||||||
static int add_addresses(struct addrinfo *);
|
#define ERRMSG_SIZE 256
|
||||||
static struct in_addr *copy_addr4(void);
|
|
||||||
|
struct param {
|
||||||
|
struct iovec name;
|
||||||
|
struct iovec value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct param *params;
|
||||||
|
static char **param_values;
|
||||||
|
static int nparams;
|
||||||
|
|
||||||
|
static char *ip4_addr;
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
static struct in6_addr *copy_addr6(void);
|
static char *ip6_addr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern char **environ;
|
static void add_ip_addr(char **addrp, char *newaddr);
|
||||||
|
|
||||||
struct addr4entry {
|
|
||||||
STAILQ_ENTRY(addr4entry) addr4entries;
|
|
||||||
struct in_addr ip4;
|
|
||||||
int count;
|
|
||||||
};
|
|
||||||
struct addr6entry {
|
|
||||||
STAILQ_ENTRY(addr6entry) addr6entries;
|
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
struct in6_addr ip6;
|
static void add_ip_addr46(char *newaddr);
|
||||||
#endif
|
#endif
|
||||||
int count;
|
static void add_ip_addrinfo(int ai_flags, char *value);
|
||||||
};
|
static void quoted_print(FILE *fp, char *str);
|
||||||
STAILQ_HEAD(addr4head, addr4entry) addr4 = STAILQ_HEAD_INITIALIZER(addr4);
|
static void set_param(const char *name, char *value);
|
||||||
STAILQ_HEAD(addr6head, addr6entry) addr6 = STAILQ_HEAD_INITIALIZER(addr6);
|
static void usage(void);
|
||||||
|
|
||||||
|
extern char **environ;
|
||||||
|
|
||||||
#define GET_USER_INFO do { \
|
#define GET_USER_INFO do { \
|
||||||
pwd = getpwnam(username); \
|
pwd = getpwnam(username); \
|
||||||
@ -94,25 +98,28 @@ int
|
|||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
login_cap_t *lcap = NULL;
|
login_cap_t *lcap = NULL;
|
||||||
struct jail j;
|
struct iovec rparams[2];
|
||||||
struct passwd *pwd = NULL;
|
struct passwd *pwd = NULL;
|
||||||
gid_t groups[NGROUPS];
|
gid_t groups[NGROUPS];
|
||||||
int ch, error, i, ngroups, securelevel;
|
int ch, cmdarg, i, jail_set_flags, jid, ngroups;
|
||||||
int hflag, iflag, Jflag, lflag, uflag, Uflag;
|
int hflag, iflag, Jflag, lflag, rflag, uflag, Uflag;
|
||||||
char path[PATH_MAX], *jailname, *ep, *username, *JidFile, *ip;
|
char *ep, *jailname, *securelevel, *username, *JidFile;
|
||||||
|
char errmsg[ERRMSG_SIZE];
|
||||||
static char *cleanenv;
|
static char *cleanenv;
|
||||||
const char *shell, *p = NULL;
|
const char *shell, *p = NULL;
|
||||||
long ltmp;
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct addrinfo hints, *res0;
|
|
||||||
|
|
||||||
hflag = iflag = Jflag = lflag = uflag = Uflag = 0;
|
hflag = iflag = Jflag = lflag = rflag = uflag = Uflag =
|
||||||
securelevel = -1;
|
jail_set_flags = 0;
|
||||||
jailname = username = JidFile = cleanenv = NULL;
|
cmdarg = jid = -1;
|
||||||
|
jailname = securelevel = username = JidFile = cleanenv = NULL;
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "hiln:s:u:U:J:")) != -1) {
|
while ((ch = getopt(argc, argv, "cdhilmn:r:s:u:U:J:")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
|
case 'd':
|
||||||
|
jail_set_flags |= JAIL_DYING;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
hflag = 1;
|
hflag = 1;
|
||||||
break;
|
break;
|
||||||
@ -127,10 +134,7 @@ main(int argc, char **argv)
|
|||||||
jailname = optarg;
|
jailname = optarg;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
ltmp = strtol(optarg, &ep, 0);
|
securelevel = optarg;
|
||||||
if (*ep || ep == optarg || ltmp > INT_MAX || !ltmp)
|
|
||||||
errx(1, "invalid securelevel: `%s'", optarg);
|
|
||||||
securelevel = ltmp;
|
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
username = optarg;
|
username = optarg;
|
||||||
@ -143,13 +147,39 @@ main(int argc, char **argv)
|
|||||||
case 'l':
|
case 'l':
|
||||||
lflag = 1;
|
lflag = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
jail_set_flags |= JAIL_CREATE;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
jail_set_flags |= JAIL_UPDATE;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
jid = strtoul(optarg, &ep, 10);
|
||||||
|
if (!*optarg || *ep) {
|
||||||
|
*(const void **)&rparams[0].iov_base = "name";
|
||||||
|
rparams[0].iov_len = sizeof("name");
|
||||||
|
rparams[1].iov_base = optarg;
|
||||||
|
rparams[1].iov_len = strlen(optarg) + 1;
|
||||||
|
jid = jail_get(rparams, 2, 0);
|
||||||
|
if (jid < 0)
|
||||||
|
errx(1, "unknown jail: %s", optarg);
|
||||||
|
}
|
||||||
|
rflag = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
if (argc < 4)
|
if (rflag) {
|
||||||
|
if (argc > 0 || iflag || Jflag || lflag || uflag || Uflag)
|
||||||
|
usage();
|
||||||
|
if (jail_remove(jid) < 0)
|
||||||
|
err(1, "jail_remove");
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
if (argc == 0)
|
||||||
usage();
|
usage();
|
||||||
if (uflag && Uflag)
|
if (uflag && Uflag)
|
||||||
usage();
|
usage();
|
||||||
@ -157,92 +187,118 @@ main(int argc, char **argv)
|
|||||||
usage();
|
usage();
|
||||||
if (uflag)
|
if (uflag)
|
||||||
GET_USER_INFO;
|
GET_USER_INFO;
|
||||||
if (realpath(argv[0], path) == NULL)
|
|
||||||
err(1, "realpath: %s", argv[0]);
|
|
||||||
if (chdir(path) != 0)
|
|
||||||
err(1, "chdir: %s", path);
|
|
||||||
/* Initialize struct jail. */
|
|
||||||
memset(&j, 0, sizeof(j));
|
|
||||||
j.version = JAIL_API_VERSION;
|
|
||||||
j.path = path;
|
|
||||||
j.hostname = argv[1];
|
|
||||||
if (jailname != NULL)
|
|
||||||
j.jailname = jailname;
|
|
||||||
|
|
||||||
/* Handle IP addresses. If requested resolve hostname too. */
|
/*
|
||||||
bzero(&hints, sizeof(struct addrinfo));
|
* If the first argument (path) starts with a slash, and the third
|
||||||
hints.ai_protocol = IPPROTO_TCP;
|
* argument (IP address) starts with a digit, it is likely to be
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
* an old-style fixed-parameter command line.
|
||||||
if (JAIL_API_VERSION < 2)
|
*/
|
||||||
hints.ai_family = PF_INET;
|
if (jailname)
|
||||||
else
|
set_param("name", jailname);
|
||||||
hints.ai_family = PF_UNSPEC;
|
if (securelevel)
|
||||||
/* Handle hostname. */
|
set_param("securelevel", securelevel);
|
||||||
if (hflag != 0) {
|
if (jail_set_flags) {
|
||||||
error = getaddrinfo(j.hostname, NULL, &hints, &res0);
|
for (i = 0; i < argc; i++) {
|
||||||
if (error != 0)
|
if (!strncmp(argv[i], "command=", 8)) {
|
||||||
errx(1, "failed to handle hostname: %s",
|
cmdarg = i;
|
||||||
gai_strerror(error));
|
argv[cmdarg] += 8;
|
||||||
error = add_addresses(res0);
|
jail_set_flags |= JAIL_ATTACH;
|
||||||
freeaddrinfo(res0);
|
break;
|
||||||
if (error != 0)
|
}
|
||||||
errx(1, "failed to add addresses.");
|
if (hflag) {
|
||||||
}
|
if (!strncmp(argv[i], "ip4.addr=", 9)) {
|
||||||
/* Handle IP addresses. */
|
add_ip_addr(&ip4_addr, argv[i] + 9);
|
||||||
hints.ai_flags = AI_NUMERICHOST;
|
break;
|
||||||
ip = strtok(argv[2], ",");
|
}
|
||||||
while (ip != NULL) {
|
|
||||||
error = getaddrinfo(ip, NULL, &hints, &res0);
|
|
||||||
if (error != 0)
|
|
||||||
errx(1, "failed to handle ip: %s", gai_strerror(error));
|
|
||||||
error = add_addresses(res0);
|
|
||||||
freeaddrinfo(res0);
|
|
||||||
if (error != 0)
|
|
||||||
errx(1, "failed to add addresses.");
|
|
||||||
ip = strtok(NULL, ",");
|
|
||||||
}
|
|
||||||
/* Count IP addresses and add them to struct jail. */
|
|
||||||
if (!STAILQ_EMPTY(&addr4)) {
|
|
||||||
j.ip4s = STAILQ_FIRST(&addr4)->count;
|
|
||||||
j.ip4 = copy_addr4();
|
|
||||||
if (j.ip4s > 0 && j.ip4 == NULL)
|
|
||||||
errx(1, "copy_addr4()");
|
|
||||||
}
|
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
if (!STAILQ_EMPTY(&addr6)) {
|
if (!strncmp(argv[i], "ip6.addr=", 9)) {
|
||||||
j.ip6s = STAILQ_FIRST(&addr6)->count;
|
add_ip_addr(&ip6_addr, argv[i] + 9);
|
||||||
j.ip6 = copy_addr6();
|
break;
|
||||||
if (j.ip6s > 0 && j.ip6 == NULL)
|
}
|
||||||
errx(1, "copy_addr6()");
|
#endif
|
||||||
|
if (!strncmp(argv[i], "host.hostname=", 14))
|
||||||
|
add_ip_addrinfo(0, argv[i] + 14);
|
||||||
|
}
|
||||||
|
set_param(NULL, argv[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (argc < 4 || argv[0][0] != '/')
|
||||||
|
errx(1, "%s\n%s",
|
||||||
|
"no -c or -m, so this must be an old-style command.",
|
||||||
|
"But it doesn't look like one.");
|
||||||
|
set_param("path", argv[0]);
|
||||||
|
set_param("host.hostname", argv[1]);
|
||||||
|
if (hflag)
|
||||||
|
add_ip_addrinfo(0, argv[1]);
|
||||||
|
#ifdef INET6
|
||||||
|
add_ip_addr46(argv[2]);
|
||||||
|
#else
|
||||||
|
add_ip_addr(&ip4_addr, argv[2]);
|
||||||
|
#endif
|
||||||
|
cmdarg = 3;
|
||||||
}
|
}
|
||||||
#endif
|
if (ip4_addr != NULL)
|
||||||
|
set_param("ip4.addr", ip4_addr);
|
||||||
|
#ifdef INET6
|
||||||
|
if (ip6_addr != NULL)
|
||||||
|
set_param("ip6.addr", ip6_addr);
|
||||||
|
#endif
|
||||||
|
errmsg[0] = 0;
|
||||||
|
set_param("errmsg", errmsg);
|
||||||
|
|
||||||
if (Jflag) {
|
if (Jflag) {
|
||||||
fp = fopen(JidFile, "w");
|
fp = fopen(JidFile, "w");
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
errx(1, "Could not create JidFile: %s", JidFile);
|
errx(1, "Could not create JidFile: %s", JidFile);
|
||||||
}
|
}
|
||||||
i = jail(&j);
|
jid = jail_set(¶ms->name, 2 * nparams,
|
||||||
if (i == -1)
|
jail_set_flags ? jail_set_flags : JAIL_CREATE | JAIL_ATTACH);
|
||||||
err(1, "syscall failed with");
|
if (jid < 0) {
|
||||||
|
if (errmsg[0] != '\0')
|
||||||
|
errx(1, "%s", errmsg);
|
||||||
|
err(1, "jail_set");
|
||||||
|
}
|
||||||
if (iflag) {
|
if (iflag) {
|
||||||
printf("%d\n", i);
|
printf("%d\n", jid);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
if (Jflag) {
|
if (Jflag) {
|
||||||
if (fp != NULL) {
|
if (jail_set_flags) {
|
||||||
fprintf(fp, "%d\t%s\t%s\t%s\t%s\n",
|
fprintf(fp, "jid=%d", jid);
|
||||||
i, j.path, j.hostname, argv[2], argv[3]);
|
for (i = 0; i < nparams; i++)
|
||||||
(void)fclose(fp);
|
if (strcmp(params[i].name.iov_base, "jid") &&
|
||||||
|
strcmp(params[i].name.iov_base, "errmsg")) {
|
||||||
|
fprintf(fp, " %s",
|
||||||
|
(char *)params[i].name.iov_base);
|
||||||
|
if (param_values[i]) {
|
||||||
|
putc('=', fp);
|
||||||
|
quoted_print(fp,
|
||||||
|
param_values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
} else {
|
} else {
|
||||||
errx(1, "Could not write JidFile: %s", JidFile);
|
for (i = 0; i < nparams; i++)
|
||||||
|
if (!strcmp(params[i].name.iov_base, "path"))
|
||||||
|
break;
|
||||||
|
#ifdef INET6
|
||||||
|
fprintf(fp, "%d\t%s\t%s\t%s%s%s\t%s\n",
|
||||||
|
jid, i < nparams
|
||||||
|
? (char *)params[i].value.iov_base : argv[0],
|
||||||
|
argv[1], ip4_addr ? ip4_addr : "",
|
||||||
|
ip4_addr && ip4_addr[0] && ip6_addr && ip6_addr[0]
|
||||||
|
? "," : "", ip6_addr ? ip6_addr : "", argv[3]);
|
||||||
|
#else
|
||||||
|
fprintf(fp, "%d\t%s\t%s\t%s\t%s\n",
|
||||||
|
jid, i < nparams
|
||||||
|
? (char *)params[i].value.iov_base : argv[0],
|
||||||
|
argv[1], ip4_addr ? ip4_addr : "", argv[3]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
(void)fclose(fp);
|
||||||
}
|
}
|
||||||
if (securelevel > 0) {
|
if (cmdarg < 0)
|
||||||
if (sysctlbyname("kern.securelevel", NULL, 0, &securelevel,
|
exit(0);
|
||||||
sizeof(securelevel)))
|
|
||||||
err(1, "Can not set securelevel to %d", securelevel);
|
|
||||||
}
|
|
||||||
if (username != NULL) {
|
if (username != NULL) {
|
||||||
if (Uflag)
|
if (Uflag)
|
||||||
GET_USER_INFO;
|
GET_USER_INFO;
|
||||||
@ -272,158 +328,328 @@ main(int argc, char **argv)
|
|||||||
if (p)
|
if (p)
|
||||||
setenv("TERM", p, 1);
|
setenv("TERM", p, 1);
|
||||||
}
|
}
|
||||||
if (execv(argv[3], argv + 3) != 0)
|
execvp(argv[cmdarg], argv + cmdarg);
|
||||||
err(1, "execv: %s", argv[3]);
|
err(1, "execvp: %s", argv[cmdarg]);
|
||||||
exit(0);
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_ip_addr(char **addrp, char *value)
|
||||||
|
{
|
||||||
|
int addrlen;
|
||||||
|
char *addr;
|
||||||
|
|
||||||
|
if (!*addrp) {
|
||||||
|
*addrp = strdup(value);
|
||||||
|
if (!*addrp)
|
||||||
|
err(1, "malloc");
|
||||||
|
} else if (value[0]) {
|
||||||
|
addrlen = strlen(*addrp) + strlen(value) + 2;
|
||||||
|
addr = malloc(addrlen);
|
||||||
|
if (!addr)
|
||||||
|
err(1, "malloc");
|
||||||
|
snprintf(addr, addrlen, "%s,%s", *addrp, value);
|
||||||
|
free(*addrp);
|
||||||
|
*addrp = addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef INET6
|
||||||
|
static void
|
||||||
|
add_ip_addr46(char *value)
|
||||||
|
{
|
||||||
|
char *p, *np;
|
||||||
|
|
||||||
|
if (!value[0]) {
|
||||||
|
add_ip_addr(&ip4_addr, value);
|
||||||
|
add_ip_addr(&ip6_addr, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (p = value;; p = np + 1)
|
||||||
|
{
|
||||||
|
np = strchr(p, ',');
|
||||||
|
if (np)
|
||||||
|
*np = '\0';
|
||||||
|
add_ip_addrinfo(AI_NUMERICHOST, p);
|
||||||
|
if (!np)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_ip_addrinfo(int ai_flags, char *value)
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *ai0, *ai;
|
||||||
|
struct in_addr addr4;
|
||||||
|
int error;
|
||||||
|
char avalue4[INET_ADDRSTRLEN];
|
||||||
|
#ifdef INET6
|
||||||
|
struct in6_addr addr6;
|
||||||
|
char avalue6[INET6_ADDRSTRLEN];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Look up the hostname (or get the address) */
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
#ifdef INET6
|
||||||
|
hints.ai_family = PF_UNSPEC;
|
||||||
|
#else
|
||||||
|
hints.ai_family = PF_INET;
|
||||||
|
#endif
|
||||||
|
hints.ai_flags = ai_flags;
|
||||||
|
error = getaddrinfo(value, NULL, &hints, &ai0);
|
||||||
|
if (error != 0)
|
||||||
|
errx(1, "hostname %s: %s", value, gai_strerror(error));
|
||||||
|
|
||||||
|
/* Convert the addresses to ASCII so set_param can convert them back. */
|
||||||
|
for (ai = ai0; ai; ai = ai->ai_next)
|
||||||
|
switch (ai->ai_family) {
|
||||||
|
case AF_INET:
|
||||||
|
memcpy(&addr4, &((struct sockaddr_in *)
|
||||||
|
(void *)ai->ai_addr)->sin_addr, sizeof(addr4));
|
||||||
|
if (inet_ntop(AF_INET, &addr4, avalue4,
|
||||||
|
INET_ADDRSTRLEN) == NULL)
|
||||||
|
err(1, "inet_ntop");
|
||||||
|
add_ip_addr(&ip4_addr, avalue4);
|
||||||
|
break;
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6:
|
||||||
|
memcpy(&addr6, &((struct sockaddr_in6 *)
|
||||||
|
(void *)ai->ai_addr)->sin6_addr, sizeof(addr6));
|
||||||
|
if (inet_ntop(AF_INET6, &addr6, avalue6,
|
||||||
|
INET6_ADDRSTRLEN) == NULL)
|
||||||
|
err(1, "inet_ntop");
|
||||||
|
add_ip_addr(&ip6_addr, avalue6);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
freeaddrinfo(ai0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
quoted_print(FILE *fp, char *str)
|
||||||
|
{
|
||||||
|
int c, qc;
|
||||||
|
char *p = str;
|
||||||
|
|
||||||
|
/* An empty string needs quoting. */
|
||||||
|
if (!*p) {
|
||||||
|
fputs("\"\"", fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The value will be surrounded by quotes if it contains spaces
|
||||||
|
* or quotes.
|
||||||
|
*/
|
||||||
|
qc = strchr(p, '\'') ? '"'
|
||||||
|
: strchr(p, '"') ? '\''
|
||||||
|
: strchr(p, ' ') || strchr(p, '\t') ? '"'
|
||||||
|
: 0;
|
||||||
|
if (qc)
|
||||||
|
putc(qc, fp);
|
||||||
|
while ((c = *p++)) {
|
||||||
|
if (c == '\\' || c == qc)
|
||||||
|
putc('\\', fp);
|
||||||
|
putc(c, fp);
|
||||||
|
}
|
||||||
|
if (qc)
|
||||||
|
putc(qc, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_param(const char *name, char *value)
|
||||||
|
{
|
||||||
|
struct param *param;
|
||||||
|
char *ep, *p;
|
||||||
|
size_t buflen, mlen;
|
||||||
|
int i, nval, mib[CTL_MAXNAME];
|
||||||
|
struct {
|
||||||
|
int i;
|
||||||
|
char s[MAXPATHLEN];
|
||||||
|
} buf;
|
||||||
|
|
||||||
|
static int paramlistsize;
|
||||||
|
|
||||||
|
/* Separate the name from the value, if not done already. */
|
||||||
|
if (name == NULL) {
|
||||||
|
name = value;
|
||||||
|
if ((value = strchr(value, '=')))
|
||||||
|
*value++ = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for repeat parameters */
|
||||||
|
for (i = 0; i < nparams; i++)
|
||||||
|
if (!strcmp(name, params[i].name.iov_base)) {
|
||||||
|
memcpy(params + i, params + i + 1,
|
||||||
|
(--nparams - i) * sizeof(struct param));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there is room for the new param record. */
|
||||||
|
if (!nparams) {
|
||||||
|
paramlistsize = 32;
|
||||||
|
params = malloc(paramlistsize * sizeof(*params));
|
||||||
|
param_values = malloc(paramlistsize * sizeof(*param_values));
|
||||||
|
if (params == NULL || param_values == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
} else if (nparams >= paramlistsize) {
|
||||||
|
paramlistsize *= 2;
|
||||||
|
params = realloc(params, paramlistsize * sizeof(*params));
|
||||||
|
param_values = realloc(param_values,
|
||||||
|
paramlistsize * sizeof(*param_values));
|
||||||
|
if (params == NULL)
|
||||||
|
err(1, "realloc");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look up the paramter. */
|
||||||
|
param_values[nparams] = value;
|
||||||
|
param = params + nparams++;
|
||||||
|
*(const void **)¶m->name.iov_base = name;
|
||||||
|
param->name.iov_len = strlen(name) + 1;
|
||||||
|
/* Trivial values - no value or errmsg. */
|
||||||
|
if (value == NULL) {
|
||||||
|
param->value.iov_base = NULL;
|
||||||
|
param->value.iov_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(name, "errmsg")) {
|
||||||
|
param->value.iov_base = value;
|
||||||
|
param->value.iov_len = ERRMSG_SIZE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mib[0] = 0;
|
||||||
|
mib[1] = 3;
|
||||||
|
snprintf(buf.s, sizeof(buf.s), SJPARAM ".%s", name);
|
||||||
|
mlen = sizeof(mib) - 2 * sizeof(int);
|
||||||
|
if (sysctl(mib, 2, mib + 2, &mlen, buf.s, strlen(buf.s)) < 0)
|
||||||
|
errx(1, "unknown parameter: %s", name);
|
||||||
|
mib[1] = 4;
|
||||||
|
buflen = sizeof(buf);
|
||||||
|
if (sysctl(mib, (mlen / sizeof(int)) + 2, &buf, &buflen, NULL, 0) < 0)
|
||||||
|
err(1, "sysctl(0.4.%s)", name);
|
||||||
|
/*
|
||||||
|
* See if this is an array type.
|
||||||
|
* Treat non-arrays as an array of one.
|
||||||
|
*/
|
||||||
|
p = strchr(buf.s, '\0');
|
||||||
|
nval = 1;
|
||||||
|
if (p - 2 >= buf.s && !strcmp(p - 2, ",a")) {
|
||||||
|
if (value[0] == '\0' ||
|
||||||
|
(value[0] == '-' && value[1] == '\0')) {
|
||||||
|
param->value.iov_base = value;
|
||||||
|
param->value.iov_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p[-2] = 0;
|
||||||
|
for (p = strchr(value, ','); p; p = strchr(p + 1, ',')) {
|
||||||
|
*p = '\0';
|
||||||
|
nval++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the values according to the parameter type. */
|
||||||
|
switch (buf.i & CTLTYPE) {
|
||||||
|
case CTLTYPE_INT:
|
||||||
|
case CTLTYPE_UINT:
|
||||||
|
param->value.iov_len = nval * sizeof(int);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_LONG:
|
||||||
|
case CTLTYPE_ULONG:
|
||||||
|
param->value.iov_len = nval * sizeof(long);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_STRUCT:
|
||||||
|
if (!strcmp(buf.s, "S,in_addr"))
|
||||||
|
param->value.iov_len = nval * sizeof(struct in_addr);
|
||||||
|
#ifdef INET6
|
||||||
|
else if (!strcmp(buf.s, "S,in6_addr"))
|
||||||
|
param->value.iov_len = nval * sizeof(struct in6_addr);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
errx(1, "%s: unknown parameter structure (%s)",
|
||||||
|
name, buf.s);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_STRING:
|
||||||
|
if (!strcmp(name, "path")) {
|
||||||
|
param->value.iov_base = malloc(MAXPATHLEN);
|
||||||
|
if (param->value.iov_base == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
if (realpath(value, param->value.iov_base) == NULL)
|
||||||
|
err(1, "%s: realpath(%s)", name, value);
|
||||||
|
if (chdir(param->value.iov_base) != 0)
|
||||||
|
err(1, "chdir: %s",
|
||||||
|
(char *)param->value.iov_base);
|
||||||
|
} else
|
||||||
|
param->value.iov_base = value;
|
||||||
|
param->value.iov_len = strlen(param->value.iov_base) + 1;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
errx(1, "%s: unknown parameter type %d (%s)",
|
||||||
|
name, buf.i, buf.s);
|
||||||
|
}
|
||||||
|
param->value.iov_base = malloc(param->value.iov_len);
|
||||||
|
for (i = 0; i < nval; i++) {
|
||||||
|
switch (buf.i & CTLTYPE) {
|
||||||
|
case CTLTYPE_INT:
|
||||||
|
((int *)param->value.iov_base)[i] =
|
||||||
|
strtol(value, &ep, 10);
|
||||||
|
if (ep[0] != '\0')
|
||||||
|
errx(1, "%s: non-integer value \"%s\"",
|
||||||
|
name, value);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_UINT:
|
||||||
|
((unsigned *)param->value.iov_base)[i] =
|
||||||
|
strtoul(value, &ep, 10);
|
||||||
|
if (ep[0] != '\0')
|
||||||
|
errx(1, "%s: non-integer value \"%s\"",
|
||||||
|
name, value);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_LONG:
|
||||||
|
((long *)param->value.iov_base)[i] =
|
||||||
|
strtol(value, &ep, 10);
|
||||||
|
if (ep[0] != '\0')
|
||||||
|
errx(1, "%s: non-integer value \"%s\"",
|
||||||
|
name, value);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_ULONG:
|
||||||
|
((unsigned long *)param->value.iov_base)[i] =
|
||||||
|
strtoul(value, &ep, 10);
|
||||||
|
if (ep[0] != '\0')
|
||||||
|
errx(1, "%s: non-integer value \"%s\"",
|
||||||
|
name, value);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_STRUCT:
|
||||||
|
if (!strcmp(buf.s, "S,in_addr")) {
|
||||||
|
if (inet_pton(AF_INET, value,
|
||||||
|
&((struct in_addr *)
|
||||||
|
param->value.iov_base)[i]) != 1)
|
||||||
|
errx(1, "%s: not an IPv4 address: %s",
|
||||||
|
name, value);
|
||||||
|
}
|
||||||
|
#ifdef INET6
|
||||||
|
else if (!strcmp(buf.s, "S,in6_addr")) {
|
||||||
|
if (inet_pton(AF_INET6, value,
|
||||||
|
&((struct in6_addr *)
|
||||||
|
param->value.iov_base)[i]) != 1)
|
||||||
|
errx(1, "%s: not an IPv6 address: %s",
|
||||||
|
name, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (i > 0)
|
||||||
|
value[-1] = ',';
|
||||||
|
value = strchr(value, '\0') + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
(void)fprintf(stderr, "%s%s%s\n",
|
(void)fprintf(stderr,
|
||||||
"usage: jail [-hi] [-n jailname] [-J jid_file] ",
|
"usage: jail [-d] [-h] [-i] [-J jid_file] "
|
||||||
"[-s securelevel] [-l -u username | -U username] ",
|
"[-l -u username | -U username]\n"
|
||||||
"path hostname [ip[,..]] command ...");
|
" [-c | -m] param=value ... [command=command ...]\n"
|
||||||
|
" jail [-r jail]\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
add_addresses(struct addrinfo *res0)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
struct addrinfo *res;
|
|
||||||
struct addr4entry *a4p;
|
|
||||||
struct sockaddr_in *sai;
|
|
||||||
#ifdef INET6
|
|
||||||
struct addr6entry *a6p;
|
|
||||||
struct sockaddr_in6 *sai6;
|
|
||||||
#endif
|
|
||||||
int count;
|
|
||||||
|
|
||||||
error = 0;
|
|
||||||
for (res = res0; res && error == 0; res = res->ai_next) {
|
|
||||||
switch (res->ai_family) {
|
|
||||||
case AF_INET:
|
|
||||||
sai = (struct sockaddr_in *)(void *)res->ai_addr;
|
|
||||||
STAILQ_FOREACH(a4p, &addr4, addr4entries) {
|
|
||||||
if (bcmp(&sai->sin_addr, &a4p->ip4,
|
|
||||||
sizeof(struct in_addr)) == 0) {
|
|
||||||
err(1, "Ignoring duplicate IPv4 address.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a4p = (struct addr4entry *) malloc(
|
|
||||||
sizeof(struct addr4entry));
|
|
||||||
if (a4p == NULL) {
|
|
||||||
error = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bzero(a4p, sizeof(struct addr4entry));
|
|
||||||
bcopy(&sai->sin_addr, &a4p->ip4,
|
|
||||||
sizeof(struct in_addr));
|
|
||||||
if (!STAILQ_EMPTY(&addr4))
|
|
||||||
count = STAILQ_FIRST(&addr4)->count;
|
|
||||||
else
|
|
||||||
count = 0;
|
|
||||||
STAILQ_INSERT_TAIL(&addr4, a4p, addr4entries);
|
|
||||||
STAILQ_FIRST(&addr4)->count = count + 1;
|
|
||||||
break;
|
|
||||||
#ifdef INET6
|
|
||||||
case AF_INET6:
|
|
||||||
sai6 = (struct sockaddr_in6 *)(void *)res->ai_addr;
|
|
||||||
STAILQ_FOREACH(a6p, &addr6, addr6entries) {
|
|
||||||
if (bcmp(&sai6->sin6_addr, &a6p->ip6,
|
|
||||||
sizeof(struct in6_addr)) == 0) {
|
|
||||||
err(1, "Ignoring duplicate IPv6 address.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a6p = (struct addr6entry *) malloc(
|
|
||||||
sizeof(struct addr6entry));
|
|
||||||
if (a6p == NULL) {
|
|
||||||
error = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bzero(a6p, sizeof(struct addr6entry));
|
|
||||||
bcopy(&sai6->sin6_addr, &a6p->ip6,
|
|
||||||
sizeof(struct in6_addr));
|
|
||||||
if (!STAILQ_EMPTY(&addr6))
|
|
||||||
count = STAILQ_FIRST(&addr6)->count;
|
|
||||||
else
|
|
||||||
count = 0;
|
|
||||||
STAILQ_INSERT_TAIL(&addr6, a6p, addr6entries);
|
|
||||||
STAILQ_FIRST(&addr6)->count = count + 1;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
err(1, "Address family %d not supported. Ignoring.\n",
|
|
||||||
res->ai_family);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct in_addr *
|
|
||||||
copy_addr4(void)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
struct in_addr *ip4s, *p, ia;
|
|
||||||
struct addr4entry *a4p;
|
|
||||||
|
|
||||||
if (STAILQ_EMPTY(&addr4))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
len = STAILQ_FIRST(&addr4)->count * sizeof(struct in_addr);
|
|
||||||
|
|
||||||
ip4s = p = (struct in_addr *)malloc(len);
|
|
||||||
if (ip4s == NULL)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
bzero(p, len);
|
|
||||||
|
|
||||||
while (!STAILQ_EMPTY(&addr4)) {
|
|
||||||
a4p = STAILQ_FIRST(&addr4);
|
|
||||||
STAILQ_REMOVE_HEAD(&addr4, addr4entries);
|
|
||||||
ia.s_addr = a4p->ip4.s_addr;
|
|
||||||
bcopy(&ia, p, sizeof(struct in_addr));
|
|
||||||
p++;
|
|
||||||
free(a4p);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ip4s);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef INET6
|
|
||||||
static struct in6_addr *
|
|
||||||
copy_addr6(void)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
struct in6_addr *ip6s, *p;
|
|
||||||
struct addr6entry *a6p;
|
|
||||||
|
|
||||||
if (STAILQ_EMPTY(&addr6))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
len = STAILQ_FIRST(&addr6)->count * sizeof(struct in6_addr);
|
|
||||||
|
|
||||||
ip6s = p = (struct in6_addr *)malloc(len);
|
|
||||||
if (ip6s == NULL)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
bzero(p, len);
|
|
||||||
|
|
||||||
while (!STAILQ_EMPTY(&addr6)) {
|
|
||||||
a6p = STAILQ_FIRST(&addr6);
|
|
||||||
STAILQ_REMOVE_HEAD(&addr6, addr6entries);
|
|
||||||
bcopy(&a6p->ip6, p, sizeof(struct in6_addr));
|
|
||||||
p++;
|
|
||||||
free(a6p);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ip6s);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
@ -6,6 +6,4 @@ DPADD= ${LIBUTIL}
|
|||||||
LDADD= -lutil
|
LDADD= -lutil
|
||||||
WARNS?= 6
|
WARNS?= 6
|
||||||
|
|
||||||
CFLAGS+= -DSUPPORT_OLD_XPRISON
|
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd November 29, 2008
|
.Dd May 27, 2009
|
||||||
.Dt JEXEC 8
|
.Dt JEXEC 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -34,36 +34,18 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl u Ar username | Fl U Ar username
|
.Op Fl u Ar username | Fl U Ar username
|
||||||
.Op Fl n Ar jailname
|
.Ar jail command ...
|
||||||
.Ar jid command ...
|
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
utility executes
|
utility executes
|
||||||
.Ar command
|
.Ar command
|
||||||
inside the jail identified by either
|
inside the
|
||||||
.Ar jailname
|
.Ar jail
|
||||||
or
|
identified by its jid or name.
|
||||||
.Ar jid
|
|
||||||
or both.
|
|
||||||
.Pp
|
|
||||||
If the jail cannot be identified uniquely by the given parameters,
|
|
||||||
an error message is printed.
|
|
||||||
.Nm
|
|
||||||
will also check the state of the jail (once supported) to be
|
|
||||||
.Dv ALIVE
|
|
||||||
and ignore jails in other states.
|
|
||||||
The mandatory argument
|
|
||||||
.Ar jid
|
|
||||||
is the unique jail identifier as given by
|
|
||||||
.Xr jls 8 .
|
|
||||||
In case you only want to match on other criteria, give an empty string.
|
|
||||||
.Pp
|
.Pp
|
||||||
The following options are available:
|
The following options are available:
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
.It Fl n Ar jailname
|
|
||||||
The name of the jail, if given upon creation of the jail.
|
|
||||||
This is not the hostname of the jail.
|
|
||||||
.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
|
||||||
|
@ -29,12 +29,16 @@
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/jail.h>
|
#include <sys/jail.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <login_cap.h>
|
#include <login_cap.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -44,153 +48,6 @@
|
|||||||
|
|
||||||
static void usage(void);
|
static void usage(void);
|
||||||
|
|
||||||
#ifdef SUPPORT_OLD_XPRISON
|
|
||||||
static
|
|
||||||
char *lookup_xprison_v1(void *p, char *end, int *id)
|
|
||||||
{
|
|
||||||
struct xprison_v1 *xp;
|
|
||||||
|
|
||||||
if (id == NULL)
|
|
||||||
errx(1, "Internal error. Invalid ID pointer.");
|
|
||||||
|
|
||||||
if ((char *)p + sizeof(struct xprison_v1) > end)
|
|
||||||
errx(1, "Invalid length for jail");
|
|
||||||
|
|
||||||
xp = (struct xprison_v1 *)p;
|
|
||||||
|
|
||||||
*id = xp->pr_id;
|
|
||||||
return ((char *)(xp + 1));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static
|
|
||||||
char *lookup_xprison_v3(void *p, char *end, int *id, char *jailname)
|
|
||||||
{
|
|
||||||
struct xprison *xp;
|
|
||||||
char *q;
|
|
||||||
int ok;
|
|
||||||
|
|
||||||
if (id == NULL)
|
|
||||||
errx(1, "Internal error. Invalid ID pointer.");
|
|
||||||
|
|
||||||
if ((char *)p + sizeof(struct xprison) > end)
|
|
||||||
errx(1, "Invalid length for jail");
|
|
||||||
|
|
||||||
xp = (struct xprison *)p;
|
|
||||||
ok = 1;
|
|
||||||
|
|
||||||
/* Jail state and name. */
|
|
||||||
if (xp->pr_state < 0 || xp->pr_state >=
|
|
||||||
(int)((sizeof(prison_states) / sizeof(struct prison_state))))
|
|
||||||
errx(1, "Invalid jail state.");
|
|
||||||
else if (xp->pr_state != PRISON_STATE_ALIVE)
|
|
||||||
ok = 0;
|
|
||||||
if (jailname != NULL) {
|
|
||||||
if (xp->pr_name[0] == '\0')
|
|
||||||
ok = 0;
|
|
||||||
else if (strcmp(jailname, xp->pr_name) != 0)
|
|
||||||
ok = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
q = (char *)(xp + 1);
|
|
||||||
/* IPv4 addresses. */
|
|
||||||
q += (xp->pr_ip4s * sizeof(struct in_addr));
|
|
||||||
if ((char *)q > end)
|
|
||||||
errx(1, "Invalid length for jail");
|
|
||||||
/* IPv6 addresses. */
|
|
||||||
q += (xp->pr_ip6s * sizeof(struct in6_addr));
|
|
||||||
if ((char *)q > end)
|
|
||||||
errx(1, "Invalid length for jail");
|
|
||||||
|
|
||||||
if (ok)
|
|
||||||
*id = xp->pr_id;
|
|
||||||
return (q);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lookup_jail(int jid, char *jailname)
|
|
||||||
{
|
|
||||||
size_t i, j, len;
|
|
||||||
void *p, *q;
|
|
||||||
int version, id, xid, count;
|
|
||||||
|
|
||||||
if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
|
|
||||||
err(1, "sysctlbyname(): security.jail.list");
|
|
||||||
|
|
||||||
j = len;
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
if (len == 0)
|
|
||||||
return (-1);
|
|
||||||
p = q = malloc(len);
|
|
||||||
if (p == NULL)
|
|
||||||
err(1, "malloc()");
|
|
||||||
|
|
||||||
if (sysctlbyname("security.jail.list", q, &len, NULL, 0) == -1) {
|
|
||||||
if (errno == ENOMEM) {
|
|
||||||
free(p);
|
|
||||||
p = NULL;
|
|
||||||
len += j;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
err(1, "sysctlbyname(): security.jail.list");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (p == NULL)
|
|
||||||
err(1, "sysctlbyname(): security.jail.list");
|
|
||||||
if (len < sizeof(int))
|
|
||||||
errx(1, "This is no prison. Kernel and userland out of sync?");
|
|
||||||
version = *(int *)p;
|
|
||||||
if (version > XPRISON_VERSION)
|
|
||||||
errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
xid = -1;
|
|
||||||
for (; q != NULL && (char *)q + sizeof(int) < (char *)p + len;) {
|
|
||||||
version = *(int *)q;
|
|
||||||
if (version > XPRISON_VERSION)
|
|
||||||
errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
|
|
||||||
id = -1;
|
|
||||||
switch (version) {
|
|
||||||
#ifdef SUPPORT_OLD_XPRISON
|
|
||||||
case 1:
|
|
||||||
if (jailname != NULL)
|
|
||||||
errx(1, "Version 1 prisons did not "
|
|
||||||
"support jail names.");
|
|
||||||
q = lookup_xprison_v1(q, (char *)p + len, &id);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
errx(1, "Version 2 was used by multi-IPv4 jail "
|
|
||||||
"implementations that never made it into the "
|
|
||||||
"official kernel.");
|
|
||||||
/* NOTREACHED */
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case 3:
|
|
||||||
q = lookup_xprison_v3(q, (char *)p + len, &id, jailname);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errx(1, "Prison unknown. Kernel/userland out of sync?");
|
|
||||||
/* NOTREACHED */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Possible match; see if we have a jail ID to match as well. */
|
|
||||||
if (id > 0 && (jid <= 0 || id == jid)) {
|
|
||||||
xid = id;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(p);
|
|
||||||
|
|
||||||
if (count == 1)
|
|
||||||
return (xid);
|
|
||||||
else if (count > 1)
|
|
||||||
errx(1, "Could not uniquely identify the jail.");
|
|
||||||
else
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GET_USER_INFO do { \
|
#define GET_USER_INFO do { \
|
||||||
pwd = getpwnam(username); \
|
pwd = getpwnam(username); \
|
||||||
if (pwd == NULL) { \
|
if (pwd == NULL) { \
|
||||||
@ -210,21 +67,20 @@ lookup_jail(int jid, char *jailname)
|
|||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
struct iovec params[2];
|
||||||
int jid;
|
int jid;
|
||||||
login_cap_t *lcap = NULL;
|
login_cap_t *lcap = NULL;
|
||||||
struct passwd *pwd = NULL;
|
struct passwd *pwd = NULL;
|
||||||
gid_t groups[NGROUPS];
|
gid_t groups[NGROUPS];
|
||||||
int ch, ngroups, uflag, Uflag;
|
int ch, ngroups, uflag, Uflag;
|
||||||
char *jailname, *username;
|
char *ep, *username;
|
||||||
|
|
||||||
ch = uflag = Uflag = 0;
|
ch = uflag = Uflag = 0;
|
||||||
jailname = username = NULL;
|
username = NULL;
|
||||||
jid = -1;
|
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "i:n:u:U:")) != -1) {
|
while ((ch = getopt(argc, argv, "nu:U:")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'n':
|
case 'n':
|
||||||
jailname = optarg;
|
/* Specified name, now unused */
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
username = optarg;
|
username = optarg;
|
||||||
@ -242,22 +98,20 @@ main(int argc, char *argv[])
|
|||||||
argv += optind;
|
argv += optind;
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
usage();
|
usage();
|
||||||
if (strlen(argv[0]) > 0) {
|
|
||||||
jid = (int)strtol(argv[0], NULL, 10);
|
|
||||||
if (errno)
|
|
||||||
err(1, "Unable to parse jail ID.");
|
|
||||||
}
|
|
||||||
if (jid <= 0 && jailname == NULL) {
|
|
||||||
fprintf(stderr, "Neither jail ID nor jail name given.\n");
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
if (uflag && Uflag)
|
if (uflag && Uflag)
|
||||||
usage();
|
usage();
|
||||||
if (uflag)
|
if (uflag)
|
||||||
GET_USER_INFO;
|
GET_USER_INFO;
|
||||||
jid = lookup_jail(jid, jailname);
|
jid = strtoul(argv[0], &ep, 10);
|
||||||
if (jid <= 0)
|
if (!*argv[0] || *ep) {
|
||||||
errx(1, "Cannot identify jail.");
|
*(const void **)¶ms[0].iov_base = "name";
|
||||||
|
params[0].iov_len = sizeof("name");
|
||||||
|
params[1].iov_base = argv[0];
|
||||||
|
params[1].iov_len = strlen(argv[0]) + 1;
|
||||||
|
jid = jail_get(params, 2, 0);
|
||||||
|
if (jid < 0)
|
||||||
|
errx(1, "Unknown jail: %s", argv[0]);
|
||||||
|
}
|
||||||
if (jail_attach(jid) == -1)
|
if (jail_attach(jid) == -1)
|
||||||
err(1, "jail_attach(): %d", jid);
|
err(1, "jail_attach(): %d", jid);
|
||||||
if (chdir("/") == -1)
|
if (chdir("/") == -1)
|
||||||
@ -283,8 +137,7 @@ static void
|
|||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf(stderr, "%s%s\n",
|
fprintf(stderr, "%s\n",
|
||||||
"usage: jexec [-u username | -U username]",
|
"usage: jexec [-u username | -U username] jail command ...");
|
||||||
" [-n jailname] jid command ...");
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,4 @@ PROG= jls
|
|||||||
MAN= jls.8
|
MAN= jls.8
|
||||||
WARNS?= 6
|
WARNS?= 6
|
||||||
|
|
||||||
CFLAGS+= -DSUPPORT_OLD_XPRISON
|
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd November 29, 2008
|
.Dd May 27, 2009
|
||||||
.Dt JLS 8
|
.Dt JLS 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -33,38 +33,68 @@
|
|||||||
.Nd "list jails"
|
.Nd "list jails"
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl av
|
.Op Fl dhnqsv
|
||||||
|
.Op Fl j Ar jail
|
||||||
|
.Op Ar parameter ...
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
utility lists all jails.
|
utility lists all active jails, or the specified jail.
|
||||||
By default only active jails are listed.
|
Each jail is represented by one row which contains space-separated values of
|
||||||
|
the listed
|
||||||
|
.Ar parameters ,
|
||||||
|
including the pseudo-parameter
|
||||||
|
.Va all
|
||||||
|
which will show all available jail parameters.
|
||||||
|
A list of available parameters can be retrieved via
|
||||||
|
.Dq Nm sysctl Fl d Va security.jail.param .
|
||||||
|
See
|
||||||
|
.Xr jail 8
|
||||||
|
for a description of some core parameters.
|
||||||
.Pp
|
.Pp
|
||||||
The options are as follows:
|
If no
|
||||||
.Bl -tag -width ".Fl a"
|
.Ar parameters
|
||||||
.It Fl a
|
are given, the following four columns will be printed:
|
||||||
Show jails in all states, not only active ones.
|
jail identifier (jid), IP address (ip4.addr), hostname (host.hostname),
|
||||||
|
and path (path).
|
||||||
|
.Pp
|
||||||
|
The following options are available:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl d
|
||||||
|
List
|
||||||
|
.Va dying
|
||||||
|
as well as active jails.
|
||||||
|
.It Fl h
|
||||||
|
Print a header line containing the parameters listed.
|
||||||
|
If no parameters are given on the command line, the default output always
|
||||||
|
contains a header.
|
||||||
|
.It Fl n
|
||||||
|
Print parameters in
|
||||||
|
.Dq name=value
|
||||||
|
format, where each parameter is preceded by its name.
|
||||||
|
This option is ignored for the default four-column output.
|
||||||
|
.It Fl q
|
||||||
|
Put quotes around parameters if they contain spaces or quotes, or are
|
||||||
|
the empty string.
|
||||||
|
.It Fl c
|
||||||
|
Print parameters suitable for passing to
|
||||||
|
.Xr jail 8 ,
|
||||||
|
skipping read-only and unused parameters.
|
||||||
|
Implies
|
||||||
|
.Fl nq .
|
||||||
.It Fl v
|
.It Fl v
|
||||||
Show more verbose information.
|
Print a multiple-line summary per jail, with the following parameters:
|
||||||
This also lists cpusets, jail state, multi-IP, etc. instead of the
|
jail identifier (jid), hostname (host.hostname), path (path),
|
||||||
classic single-IP jail output.
|
jail name (name), jail state (dying), cpuset ID (cpuset),
|
||||||
.El
|
IP address(es) (ip4.addr and ip6.addr).
|
||||||
.Pp
|
.It Fl j Ar jail
|
||||||
Each jail is represented by rows which, depending on
|
The jid or name of the
|
||||||
.Fl v ,
|
.Ar jail
|
||||||
contain the following columns:
|
to list.
|
||||||
.Bl -item -offset indent -compact
|
Without this option, all active jails will be listed.
|
||||||
.It
|
|
||||||
jail identifier (JID), hostname and path
|
|
||||||
.It
|
|
||||||
jail state and name
|
|
||||||
.It
|
|
||||||
jail cpuset
|
|
||||||
.It
|
|
||||||
followed by one IP adddress per line.
|
|
||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr jail 2 ,
|
.Xr jail_get 2 ,
|
||||||
.Xr jail 8 ,
|
.Xr jail 8 ,
|
||||||
.Xr jexec 8
|
.Xr jexec 8
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
@ -72,3 +102,5 @@ The
|
|||||||
.Nm
|
.Nm
|
||||||
utility was added in
|
utility was added in
|
||||||
.Fx 5.1 .
|
.Fx 5.1 .
|
||||||
|
Extensible jail parameters were introduced in
|
||||||
|
.Fx 8.0 .
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
|
* Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
|
||||||
* Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
|
* Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
|
||||||
|
* Copyright (c) 2009 James Gritton <jamie@FreeBSD.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -23,18 +24,20 @@
|
|||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
|
||||||
* $FreeBSD$
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/cdefs.h>
|
||||||
#include <sys/types.h>
|
__FBSDID("$FreeBSD$");
|
||||||
#include <sys/jail.h>
|
|
||||||
#include <sys/sysctl.h>
|
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/jail.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@ -43,215 +46,718 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define FLAG_A 0x00001
|
#define SJPARAM "security.jail.param"
|
||||||
#define FLAG_V 0x00002
|
#define ARRAY_SLOP 5
|
||||||
|
|
||||||
#ifdef SUPPORT_OLD_XPRISON
|
#define CTLTYPE_BOOL (CTLTYPE + 1)
|
||||||
static
|
#define CTLTYPE_NOBOOL (CTLTYPE + 2)
|
||||||
char *print_xprison_v1(void *p, char *end, unsigned flags)
|
#define CTLTYPE_IPADDR (CTLTYPE + 3)
|
||||||
|
#define CTLTYPE_IP6ADDR (CTLTYPE + 4)
|
||||||
|
|
||||||
|
#define PARAM_KEY 0x01
|
||||||
|
#define PARAM_USER 0x02
|
||||||
|
#define PARAM_ARRAY 0x04
|
||||||
|
#define PARAM_OPT 0x08
|
||||||
|
#define PARAM_WR 0x10
|
||||||
|
|
||||||
|
#define PRINT_DEFAULT 0x01
|
||||||
|
#define PRINT_HEADER 0x02
|
||||||
|
#define PRINT_NAMEVAL 0x04
|
||||||
|
#define PRINT_QUOTED 0x08
|
||||||
|
#define PRINT_SKIP 0x10
|
||||||
|
#define PRINT_VERBOSE 0x20
|
||||||
|
|
||||||
|
struct param {
|
||||||
|
char *name;
|
||||||
|
void *value;
|
||||||
|
size_t size;
|
||||||
|
int type;
|
||||||
|
unsigned flags;
|
||||||
|
int noparent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iovec2 {
|
||||||
|
struct iovec name;
|
||||||
|
struct iovec value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct param *params;
|
||||||
|
static int nparams;
|
||||||
|
static char errmsg[256];
|
||||||
|
|
||||||
|
static int add_param(const char *name, void *value, unsigned flags);
|
||||||
|
static int get_param(const char *name, struct param *param);
|
||||||
|
static int sort_param(const void *a, const void *b);
|
||||||
|
static char *noname(const char *name);
|
||||||
|
static char *nononame(const char *name);
|
||||||
|
static int print_jail(int pflags, int jflags);
|
||||||
|
static void quoted_print(char *str, int len);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct xprison_v1 *xp;
|
char *dot, *ep, *jname, *nname;
|
||||||
struct in_addr in;
|
int c, i, jflags, jid, lastjid, pflags, spc;
|
||||||
|
|
||||||
if ((char *)p + sizeof(struct xprison_v1) > end)
|
jname = NULL;
|
||||||
errx(1, "Invalid length for jail");
|
pflags = jflags = jid = 0;
|
||||||
|
while ((c = getopt(argc, argv, "adj:hnqsv")) >= 0)
|
||||||
|
switch (c) {
|
||||||
|
case 'a':
|
||||||
|
case 'd':
|
||||||
|
jflags |= JAIL_DYING;
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
jid = strtoul(optarg, &ep, 10);
|
||||||
|
if (!*optarg || *ep)
|
||||||
|
jname = optarg;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
pflags = (pflags & ~PRINT_SKIP) | PRINT_HEADER;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
pflags = (pflags & ~PRINT_VERBOSE) | PRINT_NAMEVAL;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
pflags |= PRINT_QUOTED;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
pflags = (pflags & ~(PRINT_HEADER | PRINT_VERBOSE)) |
|
||||||
|
PRINT_NAMEVAL | PRINT_QUOTED | PRINT_SKIP;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
pflags = (pflags & ~(PRINT_NAMEVAL | PRINT_SKIP)) |
|
||||||
|
PRINT_VERBOSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errx(1, "usage: jls [-dhnqv] [-j jail] [param ...]");
|
||||||
|
}
|
||||||
|
|
||||||
xp = (struct xprison_v1 *)p;
|
/* Add the parameters to print. */
|
||||||
if (flags & FLAG_V) {
|
if (optind == argc) {
|
||||||
printf("%6d %-29.29s %.74s\n",
|
if (pflags & PRINT_VERBOSE) {
|
||||||
xp->pr_id, xp->pr_host, xp->pr_path);
|
add_param("jid", NULL, PARAM_USER);
|
||||||
/* We are not printing an empty line here for state and name. */
|
add_param("host.hostname", NULL, PARAM_USER);
|
||||||
/* We are not printing an empty line here for cpusetid. */
|
add_param("path", NULL, PARAM_USER);
|
||||||
/* IPv4 address. */
|
add_param("name", NULL, PARAM_USER);
|
||||||
in.s_addr = htonl(xp->pr_ip);
|
add_param("dying", NULL, PARAM_USER);
|
||||||
printf("%6s %-15.15s\n", "", inet_ntoa(in));
|
add_param("cpuset", NULL, PARAM_USER);
|
||||||
} else {
|
add_param("ip4.addr", NULL, PARAM_USER);
|
||||||
printf("%6d %-15.15s %-29.29s %.74s\n",
|
add_param("ip6.addr", NULL, PARAM_USER | PARAM_OPT);
|
||||||
xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path);
|
} else {
|
||||||
}
|
pflags = (pflags &
|
||||||
|
~(PRINT_NAMEVAL | PRINT_SKIP | PRINT_VERBOSE)) |
|
||||||
|
PRINT_DEFAULT;
|
||||||
|
add_param("jid", NULL, PARAM_USER);
|
||||||
|
add_param("ip4.addr", NULL, PARAM_USER);
|
||||||
|
add_param("host.hostname", NULL, PARAM_USER);
|
||||||
|
add_param("path", NULL, PARAM_USER);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
while (optind < argc)
|
||||||
|
add_param(argv[optind++], NULL, PARAM_USER);
|
||||||
|
|
||||||
return ((char *)(xp + 1));
|
if (pflags & PRINT_SKIP) {
|
||||||
}
|
/* Check for parameters with boolean parents. */
|
||||||
#endif
|
for (i = 0; i < nparams; i++) {
|
||||||
|
if ((params[i].flags & PARAM_USER) &&
|
||||||
static
|
(dot = strchr(params[i].name, '.'))) {
|
||||||
char *print_xprison_v3(void *p, char *end, unsigned flags)
|
*dot = 0;
|
||||||
{
|
nname = noname(params[i].name);
|
||||||
struct xprison *xp;
|
*dot = '.';
|
||||||
struct in_addr *iap, in;
|
params[i].noparent =
|
||||||
struct in6_addr *ia6p;
|
add_param(nname, NULL, PARAM_OPT);
|
||||||
char buf[INET6_ADDRSTRLEN];
|
free(nname);
|
||||||
const char *state;
|
}
|
||||||
char *q;
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
if ((char *)p + sizeof(struct xprison) > end)
|
|
||||||
errx(1, "Invalid length for jail");
|
|
||||||
xp = (struct xprison *)p;
|
|
||||||
|
|
||||||
if (xp->pr_state < 0 || xp->pr_state >= (int)
|
|
||||||
((sizeof(prison_states) / sizeof(struct prison_state))))
|
|
||||||
state = "(bogus)";
|
|
||||||
else
|
|
||||||
state = prison_states[xp->pr_state].state_name;
|
|
||||||
|
|
||||||
/* See if we should print non-ACTIVE jails. No? */
|
|
||||||
if ((flags & FLAG_A) == 0 && strcmp(state, "ALIVE")) {
|
|
||||||
q = (char *)(xp + 1);
|
|
||||||
q += (xp->pr_ip4s * sizeof(struct in_addr));
|
|
||||||
if (q > end)
|
|
||||||
errx(1, "Invalid length for jail");
|
|
||||||
q += (xp->pr_ip6s * sizeof(struct in6_addr));
|
|
||||||
if (q > end)
|
|
||||||
errx(1, "Invalid length for jail");
|
|
||||||
return (q);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & FLAG_V)
|
|
||||||
printf("%6d %-29.29s %.74s\n",
|
|
||||||
xp->pr_id, xp->pr_host, xp->pr_path);
|
|
||||||
|
|
||||||
/* Jail state and name. */
|
|
||||||
if (flags & FLAG_V)
|
|
||||||
printf("%6s %-29.29s %.74s\n",
|
|
||||||
"", (xp->pr_name[0] != '\0') ? xp->pr_name : "", state);
|
|
||||||
|
|
||||||
/* cpusetid. */
|
|
||||||
if (flags & FLAG_V)
|
|
||||||
printf("%6s %-6d\n",
|
|
||||||
"", xp->pr_cpusetid);
|
|
||||||
|
|
||||||
q = (char *)(xp + 1);
|
|
||||||
/* IPv4 addresses. */
|
|
||||||
iap = (struct in_addr *)(void *)q;
|
|
||||||
q += (xp->pr_ip4s * sizeof(struct in_addr));
|
|
||||||
if (q > end)
|
|
||||||
errx(1, "Invalid length for jail");
|
|
||||||
in.s_addr = 0;
|
|
||||||
for (i = 0; i < xp->pr_ip4s; i++) {
|
|
||||||
if (i == 0 || flags & FLAG_V)
|
|
||||||
in.s_addr = iap[i].s_addr;
|
|
||||||
if (flags & FLAG_V)
|
|
||||||
printf("%6s %-15.15s\n", "", inet_ntoa(in));
|
|
||||||
}
|
|
||||||
/* IPv6 addresses. */
|
|
||||||
ia6p = (struct in6_addr *)(void *)q;
|
|
||||||
q += (xp->pr_ip6s * sizeof(struct in6_addr));
|
|
||||||
if (q > end)
|
|
||||||
errx(1, "Invalid length for jail");
|
|
||||||
for (i = 0; i < xp->pr_ip6s; i++) {
|
|
||||||
if (flags & FLAG_V) {
|
|
||||||
inet_ntop(AF_INET6, &ia6p[i], buf, sizeof(buf));
|
|
||||||
printf("%6s %s\n", "", buf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If requested print the old style single line version. */
|
/* Add the index key and errmsg parameters. */
|
||||||
if (!(flags & FLAG_V))
|
if (jid != 0)
|
||||||
printf("%6d %-15.15s %-29.29s %.74s\n",
|
add_param("jid", &jid, PARAM_KEY);
|
||||||
xp->pr_id, (in.s_addr) ? inet_ntoa(in) : "",
|
else if (jname != NULL)
|
||||||
xp->pr_host, xp->pr_path);
|
add_param("name", jname, PARAM_KEY);
|
||||||
|
else
|
||||||
|
add_param("lastjid", &lastjid, PARAM_KEY);
|
||||||
|
add_param("errmsg", errmsg, PARAM_KEY);
|
||||||
|
|
||||||
return (q);
|
/* Print a header line if requested. */
|
||||||
|
if (pflags & PRINT_VERBOSE)
|
||||||
|
printf(" JID Hostname Path\n"
|
||||||
|
" Name State\n"
|
||||||
|
" CPUSetID\n"
|
||||||
|
" IP Address(es)\n");
|
||||||
|
else if (pflags & PRINT_DEFAULT)
|
||||||
|
printf(" JID IP Address "
|
||||||
|
"Hostname Path\n");
|
||||||
|
else if (pflags & PRINT_HEADER) {
|
||||||
|
for (i = spc = 0; i < nparams; i++)
|
||||||
|
if (params[i].flags & PARAM_USER) {
|
||||||
|
if (spc)
|
||||||
|
putchar(' ');
|
||||||
|
else
|
||||||
|
spc = 1;
|
||||||
|
fputs(params[i].name, stdout);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fetch the jail(s) and print the paramters. */
|
||||||
|
if (jid != 0 || jname != NULL) {
|
||||||
|
if (print_jail(pflags, jflags) < 0) {
|
||||||
|
if (errmsg[0])
|
||||||
|
errx(1, "%s", errmsg);
|
||||||
|
err(1, "jail_get");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (lastjid = 0;
|
||||||
|
(lastjid = print_jail(pflags, jflags)) >= 0; )
|
||||||
|
;
|
||||||
|
if (errno != 0 && errno != ENOENT) {
|
||||||
|
if (errmsg[0])
|
||||||
|
errx(1, "%s", errmsg);
|
||||||
|
err(1, "jail_get");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
add_param(const char *name, void *value, unsigned flags)
|
||||||
|
{
|
||||||
|
struct param *param;
|
||||||
|
char *nname;
|
||||||
|
size_t mlen1, mlen2, buflen;
|
||||||
|
int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2];
|
||||||
|
int i, tnparams;
|
||||||
|
char buf[MAXPATHLEN];
|
||||||
|
|
||||||
|
static int paramlistsize;
|
||||||
|
|
||||||
|
/* The pseudo-parameter "all" scans the list of available parameters. */
|
||||||
|
if (!strcmp(name, "all")) {
|
||||||
|
tnparams = nparams;
|
||||||
|
mib1[0] = 0;
|
||||||
|
mib1[1] = 2;
|
||||||
|
mlen1 = CTL_MAXNAME - 2;
|
||||||
|
if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0)
|
||||||
|
err(1, "sysctlnametomib(" SJPARAM ")");
|
||||||
|
for (;;) {
|
||||||
|
/* Get the next parameter. */
|
||||||
|
mlen2 = sizeof(mib2);
|
||||||
|
if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0)
|
||||||
|
err(1, "sysctl(0.2)");
|
||||||
|
if (mib2[0] != mib1[2] || mib2[1] != mib1[3] ||
|
||||||
|
mib2[2] != mib1[4])
|
||||||
|
break;
|
||||||
|
/* Convert it to an ascii name. */
|
||||||
|
memcpy(mib1 + 2, mib2, mlen2);
|
||||||
|
mlen1 = mlen2 / sizeof(int);
|
||||||
|
mib1[1] = 1;
|
||||||
|
buflen = sizeof(buf);
|
||||||
|
if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0)
|
||||||
|
err(1, "sysctl(0.1)");
|
||||||
|
add_param(buf + sizeof(SJPARAM), NULL, flags);
|
||||||
|
/*
|
||||||
|
* Convert nobool parameters to bool if their
|
||||||
|
* counterpart is a node, ortherwise discard them.
|
||||||
|
*/
|
||||||
|
param = ¶ms[nparams - 1];
|
||||||
|
if (param->type == CTLTYPE_NOBOOL) {
|
||||||
|
nname = nononame(param->name);
|
||||||
|
if (get_param(nname, param) >= 0 &&
|
||||||
|
param->type != CTLTYPE_NODE) {
|
||||||
|
free(nname);
|
||||||
|
nparams--;
|
||||||
|
} else {
|
||||||
|
free(param->name);
|
||||||
|
param->name = nname;
|
||||||
|
param->type = CTLTYPE_BOOL;
|
||||||
|
param->size = sizeof(int);
|
||||||
|
param->value = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mib1[1] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(params + tnparams, (size_t)(nparams - tnparams),
|
||||||
|
sizeof(struct param), sort_param);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for repeat parameters. */
|
||||||
|
for (i = 0; i < nparams; i++)
|
||||||
|
if (!strcmp(name, params[i].name)) {
|
||||||
|
params[i].value = value;
|
||||||
|
params[i].flags |= flags;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there is room for the new param record. */
|
||||||
|
if (!nparams) {
|
||||||
|
paramlistsize = 32;
|
||||||
|
params = malloc(paramlistsize * sizeof(*params));
|
||||||
|
if (params == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
} else if (nparams >= paramlistsize) {
|
||||||
|
paramlistsize *= 2;
|
||||||
|
params = realloc(params, paramlistsize * sizeof(*params));
|
||||||
|
if (params == NULL)
|
||||||
|
err(1, "realloc");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look up the parameter. */
|
||||||
|
param = params + nparams++;
|
||||||
|
memset(param, 0, sizeof *param);
|
||||||
|
param->name = strdup(name);
|
||||||
|
if (param->name == NULL)
|
||||||
|
err(1, "strdup");
|
||||||
|
param->flags = flags;
|
||||||
|
param->noparent = -1;
|
||||||
|
/* We have to know about pseudo-parameters without asking. */
|
||||||
|
if (!strcmp(param->name, "lastjid")) {
|
||||||
|
param->type = CTLTYPE_INT;
|
||||||
|
param->size = sizeof(int);
|
||||||
|
goto got_type;
|
||||||
|
}
|
||||||
|
if (!strcmp(param->name, "errmsg")) {
|
||||||
|
param->type = CTLTYPE_STRING;
|
||||||
|
param->size = sizeof(errmsg);
|
||||||
|
goto got_type;
|
||||||
|
}
|
||||||
|
if (get_param(name, param) < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
err(1, "sysctl(0.3.%s)", name);
|
||||||
|
/* See if this the "no" part of an existing boolean. */
|
||||||
|
if ((nname = nononame(name))) {
|
||||||
|
i = get_param(nname, param);
|
||||||
|
free(nname);
|
||||||
|
if (i >= 0 && param->type == CTLTYPE_BOOL) {
|
||||||
|
param->type = CTLTYPE_NOBOOL;
|
||||||
|
goto got_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flags & PARAM_OPT) {
|
||||||
|
nparams--;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
errx(1, "unknown parameter: %s", name);
|
||||||
|
}
|
||||||
|
if (param->type == CTLTYPE_NODE) {
|
||||||
|
/*
|
||||||
|
* A node isn't normally a parameter, but may be a boolean
|
||||||
|
* if its "no" counterpart exists.
|
||||||
|
*/
|
||||||
|
nname = noname(name);
|
||||||
|
i = get_param(nname, param);
|
||||||
|
free(nname);
|
||||||
|
if (i >= 0 && param->type == CTLTYPE_NOBOOL) {
|
||||||
|
param->type = CTLTYPE_BOOL;
|
||||||
|
goto got_type;
|
||||||
|
}
|
||||||
|
errx(1, "unknown parameter: %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
got_type:
|
||||||
|
param->value = value;
|
||||||
|
return param - params;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_param(const char *name, struct param *param)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
size_t buflen, mlen;
|
||||||
|
int mib[CTL_MAXNAME];
|
||||||
|
struct {
|
||||||
|
int i;
|
||||||
|
char s[MAXPATHLEN];
|
||||||
|
} buf;
|
||||||
|
|
||||||
|
/* Look up the MIB. */
|
||||||
|
mib[0] = 0;
|
||||||
|
mib[1] = 3;
|
||||||
|
snprintf(buf.s, sizeof(buf.s), SJPARAM ".%s", name);
|
||||||
|
mlen = sizeof(mib) - 2 * sizeof(int);
|
||||||
|
if (sysctl(mib, 2, mib + 2, &mlen, buf.s, strlen(buf.s)) < 0)
|
||||||
|
return (-1);
|
||||||
|
/* Get the type and size. */
|
||||||
|
mib[1] = 4;
|
||||||
|
buflen = sizeof(buf);
|
||||||
|
if (sysctl(mib, (mlen / sizeof(int)) + 2, &buf, &buflen, NULL, 0) < 0)
|
||||||
|
err(1, "sysctl(0.4.%s)", name);
|
||||||
|
param->type = buf.i & CTLTYPE;
|
||||||
|
if (buf.i & (CTLFLAG_WR | CTLFLAG_TUN))
|
||||||
|
param->flags |= PARAM_WR;
|
||||||
|
p = strchr(buf.s, '\0');
|
||||||
|
if (p - 2 >= buf.s && !strcmp(p - 2, ",a")) {
|
||||||
|
p[-2] = 0;
|
||||||
|
param->flags |= PARAM_ARRAY;
|
||||||
|
}
|
||||||
|
switch (param->type) {
|
||||||
|
case CTLTYPE_INT:
|
||||||
|
/* An integer parameter might be a boolean. */
|
||||||
|
if (buf.s[0] == 'B')
|
||||||
|
param->type = buf.s[1] == 'N'
|
||||||
|
? CTLTYPE_NOBOOL : CTLTYPE_BOOL;
|
||||||
|
case CTLTYPE_UINT:
|
||||||
|
param->size = sizeof(int);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_LONG:
|
||||||
|
case CTLTYPE_ULONG:
|
||||||
|
param->size = sizeof(long);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_STRUCT:
|
||||||
|
if (!strcmp(buf.s, "S,in_addr")) {
|
||||||
|
param->type = CTLTYPE_IPADDR;
|
||||||
|
param->size = sizeof(struct in_addr);
|
||||||
|
} else if (!strcmp(buf.s, "S,in6_addr")) {
|
||||||
|
param->type = CTLTYPE_IP6ADDR;
|
||||||
|
param->size = sizeof(struct in6_addr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CTLTYPE_STRING:
|
||||||
|
buf.s[0] = 0;
|
||||||
|
sysctl(mib + 2, mlen / sizeof(int), buf.s, &buflen, NULL, 0);
|
||||||
|
param->size = strtoul(buf.s, NULL, 10);
|
||||||
|
if (param->size == 0)
|
||||||
|
param->size = BUFSIZ;
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sort_param(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct param *parama, *paramb;
|
||||||
|
char *ap, *bp;
|
||||||
|
|
||||||
|
/* Put top-level parameters first. */
|
||||||
|
parama = a;
|
||||||
|
paramb = b;
|
||||||
|
ap = strchr(parama->name, '.');
|
||||||
|
bp = strchr(paramb->name, '.');
|
||||||
|
if (ap && !bp)
|
||||||
|
return (1);
|
||||||
|
if (bp && !ap)
|
||||||
|
return (-1);
|
||||||
|
return (strcmp(parama->name, paramb->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
noname(const char *name)
|
||||||
|
{
|
||||||
|
char *nname, *p;
|
||||||
|
|
||||||
|
nname = malloc(strlen(name) + 3);
|
||||||
|
if (nname == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
p = strrchr(name, '.');
|
||||||
|
if (p != NULL)
|
||||||
|
sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1);
|
||||||
|
else
|
||||||
|
sprintf(nname, "no%s", name);
|
||||||
|
return nname;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
nononame(const char *name)
|
||||||
|
{
|
||||||
|
char *nname, *p;
|
||||||
|
|
||||||
|
p = strrchr(name, '.');
|
||||||
|
if (strncmp(p ? p + 1 : name, "no", 2))
|
||||||
|
return NULL;
|
||||||
|
nname = malloc(strlen(name) - 1);
|
||||||
|
if (nname == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
if (p != NULL)
|
||||||
|
sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3);
|
||||||
|
else
|
||||||
|
strcpy(nname, name + 2);
|
||||||
|
return nname;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
print_jail(int pflags, int jflags)
|
||||||
|
{
|
||||||
|
char *nname;
|
||||||
|
int i, ai, jid, count, sanity, spc;
|
||||||
|
char ipbuf[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
static struct iovec2 *iov, *aiov;
|
||||||
|
static int narray, nkey;
|
||||||
|
|
||||||
|
/* Set up the parameter list(s) the first time around. */
|
||||||
|
if (iov == NULL) {
|
||||||
|
iov = malloc(nparams * sizeof(struct iovec2));
|
||||||
|
if (iov == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
for (i = narray = 0; i < nparams; i++) {
|
||||||
|
iov[i].name.iov_base = params[i].name;
|
||||||
|
iov[i].name.iov_len = strlen(params[i].name) + 1;
|
||||||
|
iov[i].value.iov_base = params[i].value;
|
||||||
|
iov[i].value.iov_len =
|
||||||
|
params[i].type == CTLTYPE_STRING &&
|
||||||
|
params[i].value != NULL &&
|
||||||
|
((char *)params[i].value)[0] != '\0'
|
||||||
|
? strlen(params[i].value) + 1 : params[i].size;
|
||||||
|
if (params[i].flags & (PARAM_KEY | PARAM_ARRAY)) {
|
||||||
|
narray++;
|
||||||
|
if (params[i].flags & PARAM_KEY)
|
||||||
|
nkey++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (narray > nkey) {
|
||||||
|
aiov = malloc(narray * sizeof(struct iovec2));
|
||||||
|
if (aiov == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
for (i = ai = 0; i < nparams; i++)
|
||||||
|
if (params[i].flags &
|
||||||
|
(PARAM_KEY | PARAM_ARRAY))
|
||||||
|
aiov[ai++] = iov[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If there are array parameters, find their sizes. */
|
||||||
|
if (aiov != NULL) {
|
||||||
|
for (ai = 0; ai < narray; ai++)
|
||||||
|
if (aiov[ai].value.iov_base == NULL)
|
||||||
|
aiov[ai].value.iov_len = 0;
|
||||||
|
if (jail_get((struct iovec *)aiov, 2 * narray, jflags) < 0)
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
/* Allocate storage for all parameters. */
|
||||||
|
for (i = ai = 0; i < nparams; i++) {
|
||||||
|
if (params[i].flags & (PARAM_KEY | PARAM_ARRAY)) {
|
||||||
|
if (params[i].flags & PARAM_ARRAY) {
|
||||||
|
iov[i].value.iov_len = aiov[ai].value.iov_len +
|
||||||
|
ARRAY_SLOP * params[i].size;
|
||||||
|
iov[i].value.iov_base =
|
||||||
|
malloc(iov[i].value.iov_len);
|
||||||
|
}
|
||||||
|
ai++;
|
||||||
|
} else
|
||||||
|
iov[i].value.iov_base = malloc(params[i].size);
|
||||||
|
if (iov[i].value.iov_base == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
if (params[i].value == NULL)
|
||||||
|
memset(iov[i].value.iov_base, 0, iov[i].value.iov_len);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Get the actual prison. If there are array elements, retry a few
|
||||||
|
* times in case the size changed from under us.
|
||||||
|
*/
|
||||||
|
if ((jid = jail_get((struct iovec *)iov, 2 * nparams, jflags)) < 0) {
|
||||||
|
if (errno != EINVAL || aiov == NULL || errmsg[0])
|
||||||
|
return (-1);
|
||||||
|
for (sanity = 0;; sanity++) {
|
||||||
|
if (sanity == 10)
|
||||||
|
return (-1);
|
||||||
|
for (ai = 0; ai < narray; ai++)
|
||||||
|
if (params[i].flags & PARAM_ARRAY)
|
||||||
|
aiov[ai].value.iov_len = 0;
|
||||||
|
if (jail_get((struct iovec *)iov, 2 * narray, jflags) <
|
||||||
|
0)
|
||||||
|
return (-1);
|
||||||
|
for (i = ai = 0; i < nparams; i++) {
|
||||||
|
if (!(params[i].flags &
|
||||||
|
(PARAM_KEY | PARAM_ARRAY)))
|
||||||
|
continue;
|
||||||
|
if (params[i].flags & PARAM_ARRAY) {
|
||||||
|
iov[i].value.iov_len =
|
||||||
|
aiov[ai].value.iov_len +
|
||||||
|
ARRAY_SLOP * params[i].size;
|
||||||
|
iov[i].value.iov_base =
|
||||||
|
realloc(iov[i].value.iov_base,
|
||||||
|
iov[i].value.iov_len);
|
||||||
|
if (iov[i].value.iov_base == NULL)
|
||||||
|
err(1, "malloc");
|
||||||
|
}
|
||||||
|
ai++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pflags & PRINT_VERBOSE) {
|
||||||
|
printf("%6d %-29.29s %.74s\n"
|
||||||
|
"%6s %-29.29s %.74s\n"
|
||||||
|
"%6s %-6d\n",
|
||||||
|
*(int *)iov[0].value.iov_base,
|
||||||
|
(char *)iov[1].value.iov_base,
|
||||||
|
(char *)iov[2].value.iov_base,
|
||||||
|
"",
|
||||||
|
(char *)iov[3].value.iov_base,
|
||||||
|
*(int *)iov[4].value.iov_base ? "DYING" : "ACTIVE",
|
||||||
|
"",
|
||||||
|
*(int *)iov[5].value.iov_base);
|
||||||
|
count = iov[6].value.iov_len / sizeof(struct in_addr);
|
||||||
|
for (ai = 0; ai < count; ai++)
|
||||||
|
if (inet_ntop(AF_INET,
|
||||||
|
&((struct in_addr *)iov[6].value.iov_base)[ai],
|
||||||
|
ipbuf, sizeof(ipbuf)) == NULL)
|
||||||
|
err(1, "inet_ntop");
|
||||||
|
else
|
||||||
|
printf("%6s %-15.15s\n", "", ipbuf);
|
||||||
|
if (!strcmp(params[7].name, "ip6.addr")) {
|
||||||
|
count = iov[7].value.iov_len / sizeof(struct in6_addr);
|
||||||
|
for (ai = 0; ai < count; ai++)
|
||||||
|
if (inet_ntop(AF_INET6, &((struct in_addr *)
|
||||||
|
iov[7].value.iov_base)[ai],
|
||||||
|
ipbuf, sizeof(ipbuf)) == NULL)
|
||||||
|
err(1, "inet_ntop");
|
||||||
|
else
|
||||||
|
printf("%6s %-15.15s\n", "", ipbuf);
|
||||||
|
}
|
||||||
|
} else if (pflags & PRINT_DEFAULT)
|
||||||
|
printf("%6d %-15.15s %-29.29s %.74s\n",
|
||||||
|
*(int *)iov[0].value.iov_base,
|
||||||
|
iov[1].value.iov_len == 0 ? "-"
|
||||||
|
: inet_ntoa(*(struct in_addr *)iov[1].value.iov_base),
|
||||||
|
(char *)iov[2].value.iov_base,
|
||||||
|
(char *)iov[3].value.iov_base);
|
||||||
|
else {
|
||||||
|
for (i = spc = 0; i < nparams; i++) {
|
||||||
|
if (!(params[i].flags & PARAM_USER))
|
||||||
|
continue;
|
||||||
|
if ((pflags & PRINT_SKIP) &&
|
||||||
|
((!(params[i].flags & PARAM_WR)) ||
|
||||||
|
(params[i].noparent >= 0 &&
|
||||||
|
*(int *)iov[params[i].noparent].value.iov_base)))
|
||||||
|
continue;
|
||||||
|
if (spc)
|
||||||
|
putchar(' ');
|
||||||
|
else
|
||||||
|
spc = 1;
|
||||||
|
if (pflags & PRINT_NAMEVAL) {
|
||||||
|
/*
|
||||||
|
* Generally "name=value", but for booleans
|
||||||
|
* either "name" or "noname".
|
||||||
|
*/
|
||||||
|
switch (params[i].type) {
|
||||||
|
case CTLTYPE_BOOL:
|
||||||
|
if (*(int *)iov[i].value.iov_base)
|
||||||
|
printf("%s", params[i].name);
|
||||||
|
else {
|
||||||
|
nname = noname(params[i].name);
|
||||||
|
printf("%s", nname);
|
||||||
|
free(nname);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CTLTYPE_NOBOOL:
|
||||||
|
if (*(int *)iov[i].value.iov_base)
|
||||||
|
printf("%s", params[i].name);
|
||||||
|
else {
|
||||||
|
nname =
|
||||||
|
nononame(params[i].name);
|
||||||
|
printf("%s", nname);
|
||||||
|
free(nname);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("%s=", params[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count = params[i].flags & PARAM_ARRAY
|
||||||
|
? iov[i].value.iov_len / params[i].size : 1;
|
||||||
|
if (count == 0) {
|
||||||
|
if (pflags & PRINT_QUOTED)
|
||||||
|
printf("\"\"");
|
||||||
|
else if (!(pflags & PRINT_NAMEVAL))
|
||||||
|
putchar('-');
|
||||||
|
}
|
||||||
|
for (ai = 0; ai < count; ai++) {
|
||||||
|
if (ai > 0)
|
||||||
|
putchar(',');
|
||||||
|
switch (params[i].type) {
|
||||||
|
case CTLTYPE_INT:
|
||||||
|
printf("%d", ((int *)
|
||||||
|
iov[i].value.iov_base)[ai]);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_UINT:
|
||||||
|
printf("%u", ((int *)
|
||||||
|
iov[i].value.iov_base)[ai]);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_IPADDR:
|
||||||
|
if (inet_ntop(AF_INET,
|
||||||
|
&((struct in_addr *)
|
||||||
|
iov[i].value.iov_base)[ai],
|
||||||
|
ipbuf, sizeof(ipbuf)) == NULL)
|
||||||
|
err(1, "inet_ntop");
|
||||||
|
else
|
||||||
|
printf("%s", ipbuf);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_IP6ADDR:
|
||||||
|
if (inet_ntop(AF_INET6,
|
||||||
|
&((struct in6_addr *)
|
||||||
|
iov[i].value.iov_base)[ai],
|
||||||
|
ipbuf, sizeof(ipbuf)) == NULL)
|
||||||
|
err(1, "inet_ntop");
|
||||||
|
else
|
||||||
|
printf("%s", ipbuf);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_LONG:
|
||||||
|
printf("%ld", ((long *)
|
||||||
|
iov[i].value.iov_base)[ai]);
|
||||||
|
case CTLTYPE_ULONG:
|
||||||
|
printf("%lu", ((long *)
|
||||||
|
iov[i].value.iov_base)[ai]);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_STRING:
|
||||||
|
if (pflags & PRINT_QUOTED)
|
||||||
|
quoted_print((char *)
|
||||||
|
iov[i].value.iov_base,
|
||||||
|
params[i].size);
|
||||||
|
else
|
||||||
|
printf("%.*s",
|
||||||
|
(int)params[i].size,
|
||||||
|
(char *)
|
||||||
|
iov[i].value.iov_base);
|
||||||
|
break;
|
||||||
|
case CTLTYPE_BOOL:
|
||||||
|
case CTLTYPE_NOBOOL:
|
||||||
|
if (!(pflags & PRINT_NAMEVAL))
|
||||||
|
printf(((int *)
|
||||||
|
iov[i].value.iov_base)[ai]
|
||||||
|
? "true" : "false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
for (i = 0; i < nparams; i++)
|
||||||
|
if (params[i].value == NULL)
|
||||||
|
free(iov[i].value.iov_base);
|
||||||
|
return (jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(void)
|
quoted_print(char *str, int len)
|
||||||
{
|
{
|
||||||
|
int c, qc;
|
||||||
|
char *p = str;
|
||||||
|
char *ep = str + len;
|
||||||
|
|
||||||
(void)fprintf(stderr, "usage: jls [-av]\n");
|
/* An empty string needs quoting. */
|
||||||
exit(1);
|
if (!*p) {
|
||||||
}
|
fputs("\"\"", stdout);
|
||||||
|
return;
|
||||||
int
|
}
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
/*
|
||||||
int ch, version;
|
* The value will be surrounded by quotes if it contains spaces
|
||||||
unsigned flags;
|
* or quotes.
|
||||||
size_t i, j, len;
|
*/
|
||||||
void *p, *q;
|
qc = strchr(p, '\'') ? '"'
|
||||||
|
: strchr(p, '"') ? '\''
|
||||||
flags = 0;
|
: strchr(p, ' ') || strchr(p, '\t') ? '"'
|
||||||
while ((ch = getopt(argc, argv, "av")) != -1) {
|
: 0;
|
||||||
switch (ch) {
|
if (qc)
|
||||||
case 'a':
|
putchar(qc);
|
||||||
flags |= FLAG_A;
|
while (p < ep && (c = *p++)) {
|
||||||
break;
|
if (c == '\\' || c == qc)
|
||||||
case 'v':
|
putchar('\\');
|
||||||
flags |= FLAG_V;
|
putchar(c);
|
||||||
break;
|
}
|
||||||
default:
|
if (qc)
|
||||||
usage();
|
putchar(qc);
|
||||||
}
|
|
||||||
}
|
|
||||||
argc -= optind;
|
|
||||||
argv += optind;
|
|
||||||
|
|
||||||
if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
|
|
||||||
err(1, "sysctlbyname(): security.jail.list");
|
|
||||||
|
|
||||||
j = len;
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
if (len <= 0)
|
|
||||||
exit(0);
|
|
||||||
p = q = malloc(len);
|
|
||||||
if (p == NULL)
|
|
||||||
err(1, "malloc()");
|
|
||||||
|
|
||||||
if (sysctlbyname("security.jail.list", q, &len, NULL, 0) == -1) {
|
|
||||||
if (errno == ENOMEM) {
|
|
||||||
free(p);
|
|
||||||
p = NULL;
|
|
||||||
len += j;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
err(1, "sysctlbyname(): security.jail.list");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (p == NULL)
|
|
||||||
err(1, "sysctlbyname(): security.jail.list");
|
|
||||||
if (len < sizeof(int))
|
|
||||||
errx(1, "This is no prison. Kernel and userland out of sync?");
|
|
||||||
version = *(int *)p;
|
|
||||||
if (version > XPRISON_VERSION)
|
|
||||||
errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
|
|
||||||
|
|
||||||
if (flags & FLAG_V) {
|
|
||||||
printf(" JID Hostname Path\n");
|
|
||||||
printf(" Name State\n");
|
|
||||||
printf(" CPUSetID\n");
|
|
||||||
printf(" IP Address(es)\n");
|
|
||||||
} else {
|
|
||||||
printf(" JID IP Address Hostname"
|
|
||||||
" Path\n");
|
|
||||||
}
|
|
||||||
for (; q != NULL && (char *)q + sizeof(int) < (char *)p + len;) {
|
|
||||||
version = *(int *)q;
|
|
||||||
if (version > XPRISON_VERSION)
|
|
||||||
errx(1, "Sci-Fi prison. Kernel/userland out of sync?");
|
|
||||||
switch (version) {
|
|
||||||
#ifdef SUPPORT_OLD_XPRISON
|
|
||||||
case 1:
|
|
||||||
q = print_xprison_v1(q, (char *)p + len, flags);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
errx(1, "Version 2 was used by multi-IPv4 jail "
|
|
||||||
"implementations that never made it into the "
|
|
||||||
"official kernel.");
|
|
||||||
/* NOTREACHED */
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case 3:
|
|
||||||
q = print_xprison_v3(q, (char *)p + len, flags);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errx(1, "Prison unknown. Kernel/userland out of sync?");
|
|
||||||
/* NOTREACHED */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(p);
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user