From 8bd6fc0a98539e50d96fe4b499be40c06ca63f5e Mon Sep 17 00:00:00 2001 From: anonymous Date: Fri, 27 Jun 2003 22:56:31 +0000 Subject: Initial revision --- AUTHORS | 5 + BUGS | 5 + COPYING | 14 ++ ChangeLog | 16 ++ INSTALL | 33 ++++ Makefile.am | 4 + NEWS | 1 + README | 26 +++ config.h.in | 146 +++++++++++++++ configure.ac | 42 +++++ doc/injail_man.html | 46 +++++ doc/jailer_man.html | 109 ++++++++++++ patches/jailer.patch | 179 +++++++++++++++++++ scripts/Makefile.am | 15 ++ scripts/halt | 44 +++++ scripts/reboot | 44 +++++ src/Makefile.am | 9 + src/dmesg.c | 117 ++++++++++++ src/injail.8 | 36 ++++ src/injail.c | 67 +++++++ src/injail_main.c | 51 ++++++ src/jailer.8 | 131 ++++++++++++++ src/jailer.c | 494 +++++++++++++++++++++++++++++++++++++++++++++++++++ 23 files changed, 1634 insertions(+) create mode 100755 AUTHORS create mode 100755 BUGS create mode 100755 COPYING create mode 100755 ChangeLog create mode 100755 INSTALL create mode 100755 Makefile.am create mode 100755 NEWS create mode 100755 README create mode 100755 config.h.in create mode 100755 configure.ac create mode 100755 doc/injail_man.html create mode 100755 doc/jailer_man.html create mode 100755 patches/jailer.patch create mode 100755 scripts/Makefile.am create mode 100755 scripts/halt create mode 100755 scripts/reboot create mode 100755 src/Makefile.am create mode 100755 src/dmesg.c create mode 100755 src/injail.8 create mode 100755 src/injail.c create mode 100755 src/injail_main.c create mode 100755 src/jailer.8 create mode 100755 src/jailer.c diff --git a/AUTHORS b/AUTHORS new file mode 100755 index 0000000..6ac8ee9 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +nielsen@memberwebs.com +stef0x77@yahoo.com + +Patches and Contributions: +jimquick@mac.com diff --git a/BUGS b/BUGS new file mode 100755 index 0000000..8095082 --- /dev/null +++ b/BUGS @@ -0,0 +1,5 @@ +JAILER TODOS and BUGS + +- shutdown(8) doesn't work with the halt and reboot scripts +- No console support on FreeBSD 5.0 due to devfs (will work on this shortly) +- I'm sure there's more out there. LMK at nielsen@memberwebs.com diff --git a/COPYING b/COPYING new file mode 100755 index 0000000..cf2037b --- /dev/null +++ b/COPYING @@ -0,0 +1,14 @@ +LICENSE +This software is in the public domain. + +The software is provided "as is", without warranty of any kind, +express or implied, including but not limited to the warranties +of merchantability, fitness for a particular purpose, and +noninfringement. In no event shall the author(s) be liable for any +claim, damages, or other liability, whether in an action of +contract, tort, or otherwise, arising from, out of, or in connection +with the software or the use or other dealings in the software. + +SUPPORT +Send bug reports to: + diff --git a/ChangeLog b/ChangeLog new file mode 100755 index 0000000..108137e --- /dev/null +++ b/ChangeLog @@ -0,0 +1,16 @@ +Version 1.0 + - Conditionally remove console support on FreeBSD 5.0 + +Version 1.1.2 + - Uses select when piping output from scripts + +Version 1.1.1 + - Checks to make sure it's running in a jail. + - New utility 'injail' to check from scripts whether running in a jail + - Sets process title as state changes (for ps). + +Version 1.1 + - Support the notion of a jail "console" + - Support stopping and restarting jail from inside + - jailer manages startup and shutdown and logs everything + diff --git a/INSTALL b/INSTALL new file mode 100755 index 0000000..babb319 --- /dev/null +++ b/INSTALL @@ -0,0 +1,33 @@ +====================================================================== + Jailer INSTALL + + +This software only works with FreeBSD jails. It should be installed +and run from within a full jail system. + + +QUICK INSTALLATION: + # tar -zxvf jailer-1.1.2.tar.gz + # ./configure + # make && make install + + +This installs the jailer on your system, probably in /usr/local/sbin. +To use the jailer substitute 'sh /etc/rc' with it in your jail startup +command: + + # jail /usr/jails/myjail myjailhost 192.168.2.21 /usr/local/sbin/jailer + +See jail(8) for more information. + + + +REPLACING HALT AND REBOOT COMMANDS: + +To be able to reboot the jail from inside it, copy the provided +halt and reboot scripts over your original halt and reboot commands. +Note that you should only do this inside a jail! + + # cp /usr/local/sbin/halt /usr/local/sbin/reboot /sbin + + diff --git a/Makefile.am b/Makefile.am new file mode 100755 index 0000000..ce99b8d --- /dev/null +++ b/Makefile.am @@ -0,0 +1,4 @@ +EXTRA_DIST = BUGS +SUBDIRS = src scripts + + diff --git a/NEWS b/NEWS new file mode 100755 index 0000000..c7ab92a --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ +See ChangeLog \ No newline at end of file diff --git a/README b/README new file mode 100755 index 0000000..5094f08 --- /dev/null +++ b/README @@ -0,0 +1,26 @@ +================================================================= + JAILER README + +This software is for those who have used jails and want a +controlled way to manage and shut them down etc... + + +It is to be installed inside a jail (NOT THE HOST SYSTEM) +and will manage the processes. A jailer process runs inside +each jail and manages the startup and shutdown. + + +To shutdown or restart the jail, signal the jailer process +running inside that jail. The signals are: + + + -QUIT Shutdown jail but leave jailer running + -HUP Restart the jail + -TERM Shutdown the jail and exit the jailer + + +For further jail aids see: + +http://memberwebs.com/nielsen/freebsd/jails/ + + diff --git a/config.h.in b/config.h.in new file mode 100755 index 0000000..433fc96 --- /dev/null +++ b/config.h.in @@ -0,0 +1,146 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `atexit' function. */ +#undef HAVE_ATEXIT + +/* Define to 1 if you have the `dup2' function. */ +#undef HAVE_DUP2 + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the `gethostname' function. */ +#undef HAVE_GETHOSTNAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `c' library (-lc). */ +#undef HAVE_LIBC + +/* Define to 1 if you have the `kvm' library (-lkvm). */ +#undef HAVE_LIBKVM + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PATHS_H + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the `setproctitle' function. */ +#undef HAVE_SETPROCTITLE + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#undef HAVE_STAT_EMPTY_STRING_BUG + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#undef LSTAT_FOLLOWS_SLASHED_SYMLINK + +/* Virtual jail console support disabled */ +#undef NO_CONSOLE + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if the `setvbuf' function takes the buffering type as its + second argument and the buffer pointer as the third, as on System V before + release 3. */ +#undef SETVBUF_REVERSED + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if your declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned' if does not define. */ +#undef size_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork diff --git a/configure.ac b/configure.ac new file mode 100755 index 0000000..b6d3209 --- /dev/null +++ b/configure.ac @@ -0,0 +1,42 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT(jailer, 1.2, nielsen@memberwebs.com) +AM_INIT_AUTOMAKE(jailer, 1.2) + +AC_CONFIG_SRCDIR([src/jailer.c]) +AM_CONFIG_HEADER([config.h]) + +case `uname -r` in +5.*) + echo "FreeBSD 5.x detected" + AC_DEFINE(NO_CONSOLE, 1, [Virtual jail console support disabled]) + ;; +esac + +# Checks for programs. +AC_PROG_CC + +# Checks for libraries. +AC_CHECK_LIB([kvm], [kvm_open], , + ["ERROR: This software is applicable to FreeBSD only."] ) +AC_CHECK_LIB([c], [jail], , + ["ERROR: This software requires the jail functionality of FreeBSD."] ) + +# Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([fcntl.h syslog.h unistd.h limits.h sys/file.h sys/param.h paths.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_STRUCT_TM + +# Checks for library functions. +AC_FUNC_FORK +AC_FUNC_SETVBUF_REVERSED +AC_TYPE_SIGNAL +AC_FUNC_STAT +AC_CHECK_FUNCS([dup2 gethostname strerror atexit setproctitle select]) + +AC_CONFIG_FILES([Makefile src/Makefile scripts/Makefile]) +AC_OUTPUT diff --git a/doc/injail_man.html b/doc/injail_man.html new file mode 100755 index 0000000..6854e73 --- /dev/null +++ b/doc/injail_man.html @@ -0,0 +1,46 @@ + + +
+
+
+
+
+

DESCRIPTION

+     The injail utility returns a result which indicates the jailed status of
+     the current process environment.
+
+
+
+

DIAGNOSTICS

+     The injail utility exits with one of the following values:
+     0       the process is running in a jail.
+     1       the process is not running in a jail.
+     2       an error prevented determining if the process is running in a
+             jail.
+
+
+
+

BUGS

+     injail uses kvm_getprocs(3) to determine process status. Anything which
+     could cause a failure in either kvm_open(3) or kvm_getprocs(3) can cause
+     this to fail as well. There aught to be a cleaner way.
+
+
+
+

AUTHOR

+      James E. Quick <jq@quick.com>
+
+
+
+

SEE ALSO

+     jailer(8), jail(8), kvm(3)
+
+FreeBSD 4.6                      May 28, 2002                      FreeBSD 4.6
+
+
+
+Man(1) output converted with +man2html +
+ + diff --git a/doc/jailer_man.html b/doc/jailer_man.html new file mode 100755 index 0000000..229d297 --- /dev/null +++ b/doc/jailer_man.html @@ -0,0 +1,109 @@ + + +
+
+
+
+

SYNOPSIS

+       jailer [ console-file ]
+
+
+
+

DESCRIPTION

+       jailer  manages  the  startup  and shutdown of a jail from
+       within the jail. It also  manages  the  jails  console  by
+       linking /dev/console inside the jail to a log file.
+
+       To use, replace the '/bin/sh /etc/rc' portion of your jail
+       startup command with jailer. For example instead of:
+
+        jail /jails/myjail host 10.0.1.1 /bin/sh /etc/rc
+
+       use:
+
+        jail /jails/myjail host 10.0.1.1 /usr/local/sbin/jailer
+
+
+       jailer will start the jail by  running  /etc/rc  and  then
+       remain  running  as  a  daemon inside the jail waiting for
+       signals to perform shutdown or restarts.
+
+       A shutdown is performed by first running /etc/rc.shutdown,
+       and  then  killing  all  the  processes  still  running. A
+       restart is a combination of the above.
+
+
+       The following signals have special meaning to the jailer:
+
+       HUP    Causes jailer to restart the jail. If the  jail  is
+              not running at the time it is simply started.
+
+       QUIT   Initiates  a jail shutdown.  jailer remains running
+              after processing the request.
+
+       TERM   Same as QUIT but also quits jailer.  No  more  pro-
+              cesses will be left running inside the jail.
+
+
+
+
+

JAIL CONSOLE MANAGEMENT

+       A  normal  jail  has  no console perse, and dmesg(8) reads
+       straight from the  host  kernel  message  buffer.   jailer
+       changes this to provide a virtual console for the jail.
+
+       On  jailer startup the file /var/log/console is created or
+       truncated.  /dev/console is then hard linked to  the  con-
+       sole file.
+
+       Along  with  the  jailer  distribution  you'll  find a new
+       dmesg(8) which  just  reads  from  /dev/console.   Replace
+       /sbin/dmesg(8) with this new executable and you're set.
+
+
+
+
+

OPTIONS

+       console-file
+              Overrides the default location of the  console  log
+              file, usually /var/log/console
+
+
+
+
+

FILES

+       /var/log/console
+              Virtual console file.
+
+
+
+
+

BUGS

+       Virtual  jail  consoles  don't  work with FreeBSD 5.0 yet.
+       This is due to devfs(8)
+
+       shutdown(8) doesn't work with the halt and reboot scripts.
+
+
+
+
+

AUTHOR

+       Nate Nielsen <nielsen@memberwebs.com>
+
+
+
+
+

SEE ALSO

+       jail(8), halt(8), reboot(8), dmesg(8)
+
+
+
+Version 1.2                  May 2002                   JAILER(8)
+
+
+
+Man(1) output converted with +man2html +
+ + diff --git a/patches/jailer.patch b/patches/jailer.patch new file mode 100755 index 0000000..6df5594 --- /dev/null +++ b/patches/jailer.patch @@ -0,0 +1,179 @@ +diff -Naur jailer-1.1/src/Makefile.am jailer-1.1.1/src/Makefile.am +--- jailer-1.1/src/Makefile.am Wed May 22 23:39:38 2002 ++++ jailer-1.1.1/src/Makefile.am Tue May 28 15:44:41 2002 +@@ -1,6 +1,8 @@ +-sbin_PROGRAMS = jailer dmesg +-jailer_SOURCES = jailer.c ++sbin_PROGRAMS = jailer dmesg injail ++jailer_SOURCES = jailer.c injail.c ++injail_SOURCES = injail.c injail_main.c ++LIBS = -lkvm + dmesg_SOURCES = dmesg.c +-man_MANS = jailer.8 ++man_MANS = jailer.8 injail.8 + EXTRA_DIST = $(man_MANS) + +diff -Naur jailer-1.1/src/injail.8 jailer-1.1.1/src/injail.8 +--- jailer-1.1/src/injail.8 Wed Dec 31 19:00:00 1969 ++++ jailer-1.1.1/src/injail.8 Tue May 28 16:09:55 2002 +@@ -0,0 +1,37 @@ ++.Dd May 28, 2002 ++.Dt INJAIL 8 ++.Os ++.Sh NAME ++.Nm injail ++.Nd determine if a process is running in a jail ++.Sh SYNOPSIS ++.Nm ++.Sh DESCRIPTION ++The ++.Nm ++utility returns a result which indicates the jailed status of ++the current process environment. ++.Sh DIAGNOSTICS ++The ++.Nm ++utility exits with one of the following values: ++.Bl -tag -width indent -compact ++.It 0 ++the process is running in a jail. ++.It 1 ++the process is not running in a jail. ++.It 2 ++an error prevented determining if the process is running in a jail. ++.El ++.Sh BUGS ++.Nm ++uses kvm_getprocs(3) to determine process status. Anything which ++could cause a failure in either kvm_open(3) or kvm_getprocs(3) can ++cause this to fail as well. There aught to be a cleaner way. ++.Sh AUTHOR ++ James E. Quick ++ ++.Sh SEE ALSO ++.Xr jailer 8 , ++.Xr jail 8 , ++.Xr kvm 3 +diff -Naur jailer-1.1/src/injail.c jailer-1.1.1/src/injail.c +--- jailer-1.1/src/injail.c Wed Dec 31 19:00:00 1969 ++++ jailer-1.1.1/src/injail.c Tue May 28 15:15:54 2002 +@@ -0,0 +1,52 @@ ++/* injail ++* A utility function to determine if a process is running in a ++* FreeBSD jail. ++* ++* Compiled with _INJAIL_MAIN will produce an executable to allow ++* testing from within scripts. ++* ++* This code was written by James E. Quick mailto:jq@quick.com ++* The code may be freely re-used under the terms of the BSD copyright, ++* as long as this comment remains intact. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if __FreeBSD_version > 500000 ++#define P_FLAG ki_flag ++#else ++#define P_FLAG kp_proc.p_flag ++#endif ++ ++/* int injail() ++* Return 1 if running in a jail, 0 if not, -1 on error ++* jq 05/28/2002 ++*/ ++int injail () ++{ ++ int count = 0; ++ kvm_t *kd = 0; ++ struct kinfo_proc *kp; ++ char *memf, *nlistf, *swapf, errbuf[_POSIX2_LINE_MAX]; ++ int result = -1; ++ ++ memf = nlistf = swapf = _PATH_DEVNULL; ++ kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf); ++ if (kd) { ++ kp = kvm_getprocs(kd, KERN_PROC_PID, getpid(), &count); ++ if (kp) { ++ result = (kp->P_FLAG & P_JAILED) ? 0:1; ++ } ++ kvm_close(kd); ++ } ++ ++ return result; ++} +diff -Naur jailer-1.1/src/injail_main.c jailer-1.1.1/src/injail_main.c +--- jailer-1.1/src/injail_main.c Wed Dec 31 19:00:00 1969 ++++ jailer-1.1.1/src/injail_main.c Tue May 28 15:30:01 2002 +@@ -0,0 +1,36 @@ ++/* injail ++* A utility function to determine if a process is running in a ++* FreeBSD jail. ++* ++* Compiled with _INJAIL_MAIN will produce an executable to allow ++* testing from within scripts. ++* ++* This code was written by James E. Quick mailto:jq@quick.com ++* The code may be freely re-used under the terms of the BSD copyright, ++* as long as this comment remains intact. ++*/ ++ ++#include ++ ++int injail(); ++ ++/* main for injail ++* return 0 if in a jail ++* return 1 if not in jail ++* return 2 if error prevented determining status ++* jq 05/28/2002 ++*/ ++main(int argc, char *argv[]) ++{ ++ int jailed; ++ ++ jailed = injail(); ++ if (jailed == -1) { ++ fprintf(stderr, "injail: Could not determine jailed status.\n"); ++ return 2; ++ } else if (jailed) { ++ return 0; ++ } ++ ++ return 1; ++} +diff -Naur jailer-1.1/src/jailer.c jailer-1.1.1/src/jailer.c +--- jailer-1.1/src/jailer.c Tue May 21 16:18:19 2002 ++++ jailer-1.1.1/src/jailer.c Tue May 28 15:34:32 2002 +@@ -92,15 +92,23 @@ + static void getJailName(char* buff, int buffLen); + static int createConsole(); + static int runCommand(char* command, char* header); ++int injail(); + + int main(int argc, char* argv[]) + { ++ int jailed; + char* consoleFile = CONSOLE_LOG; + FILE* console = NULL; + ++ jailed = injail(); ++ if (jailed == 0 || jailed == -1) { ++ fprintf(stderr, "jailer: Cannot determine if I am in jail.\n"); ++ return 1; ++ } + /* Get the name of the current jail */ + getJailName(g_jailName, MAX_JAIL_NAME); + ++ + if(argc > 1) + consoleFile = argv[1]; + diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100755 index 0000000..f901774 --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,15 @@ +sbin_SCRIPTS = halt reboot +EXTRA_DIST = halt reboot + +POST_INSTALL = echo ' \ +===============================================\ + To complete the installation execute the \ + following as root: \ + \ + cp $(sbindir)halt /sbin/halt \ + cp $(sbindir)reboot /sbin/reboot \ + chmod 400 /sbin/halt /sbin/reboot \ + \ + Make sure you're in a jail! \ + \ +==============================================='\ \ No newline at end of file diff --git a/scripts/halt b/scripts/halt new file mode 100755 index 0000000..f762495 --- /dev/null +++ b/scripts/halt @@ -0,0 +1,44 @@ +#!/bin/sh +# +# AUTHOR +# N. Nielsen +# +# LICENSE +# This software is in the public domain. +# +# The software is provided "as is", without warranty of any kind, +# express or implied, including but not limited to the warranties +# of merchantability, fitness for a particular purpose, and +# noninfringement. In no event shall the author(s) be liable for any +# claim, damages, or other liability, whether in an action of +# contract, tort, or otherwise, arising from, out of, or in connection +# with the software or the use or other dealings in the software. +# +# SUPPORT +# Send bug reports to: +# + +# +# 'halt' command from inside the jail + +killall=`which killall` +ret=1 + +if [ -n ${killall} ] && [ -x ${killall} ]; then + killall -QUIT jailer 2> /dev/null + ret=$? +else + ps -xa | grep "[j]ailer" | while read pid dummy; do + + kill -QUIT ${pid} 2> /dev/null + + if [ $? -eq 0 ]; then + ret=0 + fi + + done +fi + +if [ $ret -ne 0 ]; then + echo "halt: jailer not running or insufficient permissions. can't halt jail." >&2 +fi diff --git a/scripts/reboot b/scripts/reboot new file mode 100755 index 0000000..c07bd15 --- /dev/null +++ b/scripts/reboot @@ -0,0 +1,44 @@ +#!/bin/sh +# +# AUTHOR +# N. Nielsen +# +# LICENSE +# This software is in the public domain. +# +# The software is provided "as is", without warranty of any kind, +# express or implied, including but not limited to the warranties +# of merchantability, fitness for a particular purpose, and +# noninfringement. In no event shall the author(s) be liable for any +# claim, damages, or other liability, whether in an action of +# contract, tort, or otherwise, arising from, out of, or in connection +# with the software or the use or other dealings in the software. +# +# SUPPORT +# Send bug reports to: +# + +# +# 'reboot' command from inside the jail + +killall=`which killall` +ret=1 + +if [ -n ${killall} ] && [ -x ${killall} ]; then + killall -HUP jailer 2> /dev/null + ret=$? +else + ps -xa | grep "[j]ailer" | while read pid; do + + kill -HUP ${pid} 2> /dev/null + + if [ $? -eq 0 ]; then + ret=0 + fi + + done +fi + +if [ $ret -ne 0 ]; then + echo "reboot: jailer not running or insufficient permissions. can't reboot jail." >&2 +fi diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100755 index 0000000..5cf6ab4 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,9 @@ +sbin_PROGRAMS = jailer dmesg +bin_PROGRAMS = injail +jailer_SOURCES = jailer.c injail.c +dmesg_SOURCES = dmesg.c +injail_SOURCES = injail.c injail_main.c +man_MANS = jailer.8 injail.8 +LIBS = -lkvm +EXTRA_DIST = $(man_MANS) + diff --git a/src/dmesg.c b/src/dmesg.c new file mode 100755 index 0000000..af6fbbd --- /dev/null +++ b/src/dmesg.c @@ -0,0 +1,117 @@ +/* +// AUTHOR +// N. Nielsen +// +// LICENSE +// This software is in the public domain. +// +// The software is provided "as is", without warranty of any kind, +// express or implied, including but not limited to the warranties +// of merchantability, fitness for a particular purpose, and +// noninfringement. In no event shall the author(s) be liable for any +// claim, damages, or other liability, whether in an action of +// contract, tort, or otherwise, arising from, out of, or in connection +// with the software or the use or other dealings in the software. +// +// SUPPORT +// Send bug reports to: +// +// CHANGES +// 1.1 +// Initial implementation +*/ + +#define SYSLOG_NAMES + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define CONSOLE_DEV "/dev/console" + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +/* Error handlers */ +static void doWarn(const char* msg, ...); +static void doQuit(const char* msg, ...); + +static int fcopy(FILE* dest, FILE* src); + +int main(int argc, char* argv[]) +{ + FILE* console; + struct stat sb; + + /* + * Check to see if /dev/console is a real console + */ + if(stat(CONSOLE_DEV, &sb) == 0) + { + if(!(sb.st_mode & S_IFREG || sb.st_mode & S_IFLNK)) + { + doWarn("%s is not a jail console.", CONSOLE_DEV); + return 1; + } + } + + console = fopen(CONSOLE_DEV, "r"); + if(!console) + { + doQuit("couldn't open jail console: %s", strerror(errno)); + return 1; + } + + fcopy(stdout, console); + return 0; +} + +void doQuit(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + vwarnx(msg, ap); + + exit(2); + + va_end(ap); +} + +void doWarn(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + /* Either to syslog or stderr */ + vwarnx(msg, ap); + + va_end(ap); +} + + +static int fcopy(FILE* dest, FILE* src) +{ + char buff[32]; + size_t bytes = 0; + + while(!feof(src) && !ferror(src) && !ferror(dest)) + { + bytes = fread(buff, 1, 32, src); + fwrite(buff, 1, bytes, dest); + } + + if(ferror(src) || ferror(dest)) + return -1; + + return 0; +} + diff --git a/src/injail.8 b/src/injail.8 new file mode 100755 index 0000000..26345a6 --- /dev/null +++ b/src/injail.8 @@ -0,0 +1,36 @@ +.Dd May 28, 2002 +.Dt INJAIL 8 +.Os +.Sh NAME +.Nm injail +.Nd determine if a process is running in a jail +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +The +.Nm +utility returns a result which indicates the jailed status of +the current process environment. +.Sh DIAGNOSTICS +The +.Nm +utility exits with one of the following values: +.Bl -tag -width indent -compact +.It 0 +the process is running in a jail. +.It 1 +the process is not running in a jail. +.It 2 +an error prevented determining if the process is running in a jail. +.El +.Sh BUGS +.Nm +uses kvm_getprocs(3) to determine process status. Anything which +could cause a failure in either kvm_open(3) or kvm_getprocs(3) can +cause this to fail as well. There aught to be a cleaner way. +.Sh AUTHOR + James E. Quick +.Sh SEE ALSO +.Xr jailer 8 , +.Xr jail 8 , +.Xr kvm 3 \ No newline at end of file diff --git a/src/injail.c b/src/injail.c new file mode 100755 index 0000000..7d653a6 --- /dev/null +++ b/src/injail.c @@ -0,0 +1,67 @@ +/* +// AUTHOR +// James Quick +// N. Nielsen +// +// LICENSE +// This software is in the public domain. +// +// The software is provided "as is", without warranty of any kind, +// express or implied, including but not limited to the warranties +// of merchantability, fitness for a particular purpose, and +// noninfringement. In no event shall the author(s) be liable for any +// claim, damages, or other liability, whether in an action of +// contract, tort, or otherwise, arising from, out of, or in connection +// with the software or the use or other dealings in the software. +// +// SUPPORT +// Send bug reports to: +// +// injail +// A utility function to determine if a process is running in a FreeBSD jail. +// +// This code was written by James E. Quick mailto:jq@quick.com +// The code may be freely re-used under the terms of the BSD copyright, +// as long as this comment remains intact. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __FreeBSD_version > 500000 +#define P_FLAG ki_flag +#else +#define P_FLAG kp_proc.p_flag +#endif + +/* int injail() +* Return 1 if running in a jail, 0 if not, -1 on error +* jq 05/28/2002 +*/ +int injail () +{ + int count = 0; + kvm_t* kd = 0; + struct kinfo_proc* kp; + char *memf, *nlistf, *swapf, errbuf[_POSIX2_LINE_MAX]; + int result = -1; + + memf = nlistf = swapf = _PATH_DEVNULL; + kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf); + if(kd) + { + kp = kvm_getprocs(kd, KERN_PROC_PID, getpid(), &count); + if(kp) + result = (kp->P_FLAG & P_JAILED) ? 1 : 0; + kvm_close(kd); + } + + return result; +} diff --git a/src/injail_main.c b/src/injail_main.c new file mode 100755 index 0000000..aaf8034 --- /dev/null +++ b/src/injail_main.c @@ -0,0 +1,51 @@ +/* +// AUTHOR +// N. Nielsen +// James Quick +// +// LICENSE +// This software is in the public domain. +// +// The software is provided "as is", without warranty of any kind, +// express or implied, including but not limited to the warranties +// of merchantability, fitness for a particular purpose, and +// noninfringement. In no event shall the author(s) be liable for any +// claim, damages, or other liability, whether in an action of +// contract, tort, or otherwise, arising from, out of, or in connection +// with the software or the use or other dealings in the software. +// +// SUPPORT +// Send bug reports to: +// +// CHANGES +// 1.1 +// Initial implementation +// +// injail +// A utility function to determine if a process is running in a +// FreeBSD jail. +// +// This code was contributed by James E. Quick mailto:jq@quick.com +// The code may be freely re-used under the terms of the BSD copyright, +// as long as this comment remains intact. +*/ + +#include + +int injail(); + +/* main for injail + * return 0 if in a jail + * return 1 if not in jail + * return 2 if error prevented determining status + * jq 05/28/2002 + */ +main(int argc, char *argv[]) +{ + int jailed = injail(); + + if(jailed == -1) + errx(2, "Could not determine jailed status.\n"); + + return jailed ? 0 : 1; +} diff --git a/src/jailer.8 b/src/jailer.8 new file mode 100755 index 0000000..9c9b1f9 --- /dev/null +++ b/src/jailer.8 @@ -0,0 +1,131 @@ +.\" Process this file with +.\" groff -man -Tascii jailer.8 +.\" +.TH JAILER 8 "May 2002" "Version 1.2" "User Manual" +.SH NAME +.B jailer +\- manage a jail from inside +.SH SYNOPSIS +.B jailer [ +.I console-file +.B ] +.SH DESCRIPTION +.B jailer +manages the startup and shutdown of a jail from within +the jail. It also manages the jails console by linking +/dev/console inside the jail to a log file. + +To use, replace the '/bin/sh /etc/rc' portion +of your jail startup command with jailer. For example +instead of: + +.RS 1 +.B jail /jails/myjail host 10.0.1.1 /bin/sh /etc/rc +.RE 1 + +use: + +.RS 1 +.B jail /jails/myjail host 10.0.1.1 /usr/local/sbin/jailer +.RE 1 + + +.B jailer +will start the jail by running +.I /etc/rc +and then remain running as a daemon inside the jail waiting +for signals to perform shutdown or restarts. + +A shutdown is performed by first running +.IR /etc/rc.shutdown , +and then killing all the processes still running. A restart is +a combination of the above. + + +The following signals have special meaning to the jailer: +.IP HUP +Causes +.B jailer +to restart the jail. If the jail is not running at the time +it is simply started. +.IP QUIT +Initiates a jail shutdown. +.B jailer +remains running after processing the request. +.IP TERM +Same as +.I QUIT +but also quits jailer. No more processes will be left running +inside the jail. + +.SH JAIL CONSOLE MANAGEMENT +A normal jail has no console perse, and +.BR dmesg (8) +reads straight from the host kernel message buffer. +.B jailer +changes this to provide a virtual console for the jail. + +On jailer startup the file +.I /var/log/console +is created or truncated. +.I /dev/console +is then hard linked to the console file. + +Along with the jailer distribution you'll find a new +.BR dmesg (8) +which just reads from +.I /dev/console. +Replace +.BR /sbin/dmesg (8) +with this new executable and you're set. + +The output of +.B jailer +startup and shutdown operations are also output to this +virtual console. + +.SH SCRIPTS +Along with the +.B jailer +distribution come several helper scripts: + +.IP halt +This is a replacement for +.BR /sbin/halt (8) +inside the jail which signals the running +.B jailer +process. +.IP reboot +Same as above for +.BR /sbin/reboot (8) + +.SH OPTIONS +.IP console-file +Overrides the default location of the console log file, +usually +.I /var/log/console + +.SH FILES +.I /var/log/console +.RS +Virtual console file. + +.SH BUGS +Virtual jail consoles don't work with FreeBSD 5.0 yet. This is due to +.BR devfs (8) + +.BR shutdown (8) +doesn't work with the +.I halt +and +.I reboot +scripts. + +.SH AUTHOR +Nate Nielsen + +.SH "SEE ALSO" +.BR jail (8), +.BR halt (8), +.BR reboot (8), +.BR dmesg (8) diff --git a/src/jailer.c b/src/jailer.c new file mode 100755 index 0000000..8b49489 --- /dev/null +++ b/src/jailer.c @@ -0,0 +1,494 @@ +/* +// AUTHOR +// N. Nielsen +// +// LICENSE +// This software is in the public domain. +// +// The software is provided "as is", without warranty of any kind, +// express or implied, including but not limited to the warranties +// of merchantability, fitness for a particular purpose, and +// noninfringement. In no event shall the author(s) be liable for any +// claim, damages, or other liability, whether in an action of +// contract, tort, or otherwise, arising from, out of, or in connection +// with the software or the use or other dealings in the software. +// +// SUPPORT +// Send bug reports to: +// +// CHANGES +// 1.1 +// console support +// restart support +// 1.1.1 +// checks if in jail (contributed by jimquick@mac.com) +// changes process title with state +// Uses path for /dev/console from paths.h +// Doesn't fail stop if all processes in jail died during rc.shutdown +// 1.1.2 +// use select when piping script output +// +// 1.2 +// conditionally remove console support for use on FBSD 5 +*/ + +#define SYSLOG_NAMES + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +/* Length of buffer used for reading status file */ +#define FILE_BUFF_LEN 1024 + +/* Maximum length of a jail name */ +#define MAX_JAIL_NAME 256 + +/* Used when restarting before doing a SIGKILL */ +#define EXIT_TIMEOUT 5 + +#ifndef NO_CONSOLE + /* The default file for the console messages to go to */ + #define CONSOLE_LOG "/var/log/console" +#endif + +/* Headers to go to the console for startup and shutdown */ +#define START_HEADER "\nJAIL BOOT -- %s -- %s\n" +#define STOP_HEADER "\nJAIL HALT -- %s -- %s\n" + +/* The startup and shutdown commands */ +#define JAIL_START "exec 2>&1; . /etc/rc" +#define JAIL_STOP "exec 2>&1; . /etc/rc.shutdown" + +#define TITLE_START "%s (running)" +#define TITLE_STOP "%s (halted)" + +/* Set by signal handlers */ +int g_doShutdown = 0; +int g_doRestart = 0; +int g_doExit = 0; + +/* Other state */ +int g_isBackground = 0; +int g_isJailRunning = 0; +char g_jailName[MAX_JAIL_NAME]; + +/* Signal handlers */ +static void onTERM(int); +static void onHUP(int); +static void onQUIT(int); + + +/* Error handlers */ +static void doWarn(const char* msg, ...); +static void doQuit(const char* msg, ...); + +/* Main functionality */ +static int stopJail(); +static int startJail(); + +/* Helper functions */ +static void getJailName(char* buff, int buffLen); +static int runCommand(char* command, char* header); +int injail(); + +#ifndef NO_CONSOLE +static int createConsole(); +#endif + +int main(int argc, char* argv[]) +{ +#ifndef NO_CONSOLE + char* consoleFile = CONSOLE_LOG; +#endif + + /* Check if we're in a jail */ + switch(injail()) + { + case 0: + doQuit("must be run in a jail."); + break; + + case -1: + doQuit("couldn't determine if running in a jail."); + break; + } + + /* Get the name of the current jail */ + getJailName(g_jailName, MAX_JAIL_NAME); + +#ifndef NO_CONSOLE + if(argc > 1) + consoleFile = argv[1]; + + /* Create the console device properly */ + if(createConsole(consoleFile) != 0) + return 1; +#endif + + /* Start the jail */ + if(startJail() != 0) + return 1; + + /* Go into daemon mode */ + daemon(0, 0); + g_isBackground = 1; + + + + /* Catch appropriate signals */ + siginterrupt(SIGTERM, 1); + siginterrupt(SIGHUP, 1); + siginterrupt(SIGQUIT, 1); + + signal(SIGTERM, onTERM); + signal(SIGHUP, onHUP); + signal(SIGQUIT, onQUIT); + + + /* And wait! */ + while(1) + { + sleep(1); + + /* Got SIGQUIT Shutdown jail, but keep us running */ + if(g_doShutdown) + { + if(g_isJailRunning) + { + doWarn("shutting down jail: %s", g_jailName); + stopJail(); + } + + g_doShutdown = 0; + } + + + /* Got SIGHUP Stop if necessary and start jail */ + if(g_doRestart) + { + doWarn("restarting jail: %s", g_jailName); + + if(g_isJailRunning) + stopJail(); + + /* TODO: Should we start the jail again if stop fails? */ + startJail(); + + g_doRestart = 0; + } + + + /* Got SIGTERM Stop jail if necessary, then exit */ + else if(g_doExit) + { + if(g_isJailRunning) + { + doWarn("shutting down jail: %s", g_jailName); + return stopJail(); + } + + return 0; + } + } +} + + +static int startJail() +{ + /* Just run the startup command */ + int ret = runCommand(JAIL_START, START_HEADER); + if(ret < 0) + { + doWarn("couldn't run jail start script: %s\n", strerror(errno)); + return -1; + } + else + { + g_isJailRunning = 1; + setproctitle(TITLE_START, g_jailName); + return 0; + } +} + +static int stopJail() +{ + /* Run the rc.shutdown script */ + int ret = runCommand(JAIL_STOP, STOP_HEADER); + if(ret < 0) + { + doWarn("couldn't run jail shutdown script: %s\n", strerror(errno)); + return -1; + } + + + /* Kill all processes still running nicely */ + if(kill(-1, SIGTERM) == -1 || + sleep(EXIT_TIMEOUT) || + kill(-1, SIGKILL) == -1) + { + if(errno != ESRCH) + { + doWarn("couldn't stop jail %s: %s", g_jailName, strerror(errno)); + return -1; + } + } + + + setproctitle(TITLE_STOP, g_jailName); + g_isJailRunning = 0; + return 0; +} + + +/* Special function to duplicate output of a command to two + files. + + NOTE: Yes, I know this may seem like overkill, but system, + popen and all those guys would hang with certain rc scripts. + Those which opened a daemon in the background ('&') but still + kept their output going to the same stdin/stdout handles. +*/ + +/* read & write ends of a pipe */ +#define READ_END 0 +#define WRITE_END 1 + +/* pre-set file descriptors */ +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +static int runCommand(char* command, char* header) +{ + int outpipe[2]; + int pid; + + /* Create a pipe for the child process */ + if(pipe(outpipe) < 0) + return -1; + + /* Now fork*/ + switch(pid = fork()) + { + case -1: + return -1; + + /* This is the child here */ + case 0: + + { + int ret = 0; + + /* Fix up our end of the pipe */ + if(dup2(outpipe[WRITE_END], STDOUT) < 0) + return -1; + + /* Okay, now run whatever command it was */ + execl("/bin/sh", "sh", "-c", command, NULL); + + /* In case it returns then have to do this to get + children to disconnect from stdout */ + fflush(stdout); + fclose(stdout); + close(outpipe[WRITE_END]); + + exit(errno); + } + break; + + + /* And this is the parent */ + default: + { +#ifndef NO_CONSOLE + FILE* console = NULL; +#endif + time_t tm; + char buff[256]; + int ret; + int status = 0; + fd_set readmask; + struct timeval timeout = { 0, 10000 }; + + FD_ZERO(&readmask); + +#ifndef NO_CONSOLE + /* Open the console file and write the header */ + if(console = fopen(_PATH_CONSOLE, "a")) + { + setvbuf(console, NULL, _IONBF, 0); + + /* Write this stuff to the console */ + tm = time(NULL); + fprintf(console, header, g_jailName, asctime(localtime(&tm))); + } +#endif + + /* No blocking on the child processes pipe */ + fcntl(outpipe[READ_END], F_SETFL, fcntl(outpipe[READ_END], F_GETFL, 0) | O_NONBLOCK); + + /* Loop until the process dies or no more output */ + while(1) + { + FD_SET(outpipe[READ_END], &readmask); + + if(select(FD_SETSIZE, &readmask, NULL, NULL, &timeout) == -1) + doQuit("panic: select: %s", strerror(errno)); + + if(FD_ISSET(outpipe[READ_END], &readmask)) + { + /* Read a character */ + while((ret = read(outpipe[READ_END], buff, 256)) > 0) + { + /* Write it to our stdout */ + write(STDOUT, buff, ret); + +#ifndef NO_CONSOLE + /* And to our console */ + if(console) + write(fileno(console), buff, ret); +#endif + } + } + + /* If the processes exited then break out */ + if(waitpid(pid, &status, WNOHANG) == pid) + break; + + /* Or if there's an error or end of file */ + if(ret == -1 && errno != EAGAIN || ret == 0) + break; + } + + /* Return any status codes */ + if(status != 0) + return -1; + + /* Clean up */ + close(outpipe[READ_END]); + +#ifndef NO_CONSOLE + if(console) + fclose(console); +#endif + } + } + + return 0; +} + + +void doQuit(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + /* Either to syslog or stderr */ + if(g_isBackground) + vsyslog(LOG_ALERT, msg, ap); + else + vwarnx(msg, ap); + + exit(2); + + va_end(ap); +} + +void doWarn(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + /* Either to syslog or stderr */ + if(g_isBackground) + vsyslog(LOG_ALERT, msg, ap); + else + vwarnx(msg, ap); + + va_end(ap); +} + + +RETSIGTYPE onTERM(int x) +{ + g_doExit = 1; +} + +RETSIGTYPE onQUIT(int x) +{ + g_doShutdown = 1; +} + +RETSIGTYPE onHUP(int x) +{ + g_doRestart = 1; +} + + + +static void getJailName(char* buff, int buffLen) +{ + if(gethostname(buff, buffLen) == -1) + doQuit("couldn't get host name: %s", strerror(errno)); +} + +#ifndef NO_CONSOLE +static int createConsole(char* consoleFile) +{ + FILE* file = NULL; + struct stat sb; + + /* + * If we have a /dev/console already, only overwrite + * if it's not legit. ie: it's a link or a normal file. + */ + if(stat(_PATH_CONSOLE, &sb) == 0) + { + if(!(sb.st_mode & S_IFREG || sb.st_mode & S_IFLNK)) + { + doWarn("%s may be a valid console device.", _PATH_CONSOLE); + return 0; + } + } + + unlink(_PATH_CONSOLE); + + + /* + * Create the log file and console link + * Note that we overwrite the old console log file. + * TODO: We may want to make this an option to jailer + */ + if(!(file = fopen(consoleFile, "w")) || + link(consoleFile, _PATH_CONSOLE) == -1) + doWarn("couldn't do console link (%s to %s): %s", consoleFile, _PATH_CONSOLE, strerror(errno)); + + if(file) + fclose(file); + + + return 0; +} +#endif -- cgit v1.2.3