diff options
-rwxr-xr-x | AUTHORS | 5 | ||||
-rwxr-xr-x | BUGS | 5 | ||||
-rwxr-xr-x | COPYING | 14 | ||||
-rwxr-xr-x | ChangeLog | 16 | ||||
-rwxr-xr-x | INSTALL | 33 | ||||
-rwxr-xr-x | Makefile.am | 4 | ||||
-rwxr-xr-x | NEWS | 1 | ||||
-rwxr-xr-x | README | 26 | ||||
-rwxr-xr-x | config.h.in | 146 | ||||
-rwxr-xr-x | configure.ac | 42 | ||||
-rwxr-xr-x | doc/injail_man.html | 46 | ||||
-rwxr-xr-x | doc/jailer_man.html | 109 | ||||
-rwxr-xr-x | patches/jailer.patch | 179 | ||||
-rwxr-xr-x | scripts/Makefile.am | 15 | ||||
-rwxr-xr-x | scripts/halt | 44 | ||||
-rwxr-xr-x | scripts/reboot | 44 | ||||
-rwxr-xr-x | src/Makefile.am | 9 | ||||
-rwxr-xr-x | src/dmesg.c | 117 | ||||
-rwxr-xr-x | src/injail.8 | 36 | ||||
-rwxr-xr-x | src/injail.c | 67 | ||||
-rwxr-xr-x | src/injail_main.c | 51 | ||||
-rwxr-xr-x | src/jailer.8 | 131 | ||||
-rwxr-xr-x | src/jailer.c | 494 |
23 files changed, 1634 insertions, 0 deletions
@@ -0,0 +1,5 @@ +nielsen@memberwebs.com +stef0x77@yahoo.com + +Patches and Contributions: +jimquick@mac.com @@ -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 @@ -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: <nielsen@memberwebs.com> + 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 + @@ -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 + + @@ -0,0 +1 @@ +See ChangeLog
\ No newline at end of file @@ -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 <fcntl.h> 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 <inttypes.h> 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 <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the <paths.h> 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 <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> 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 <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <syslog.h> header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the <sys/file.h> header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the <unistd.h> 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 <vfork.h> 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 <sys/time.h> 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 <sys/types.h> does not define. */ +#undef pid_t + +/* Define to `unsigned' if <sys/types.h> 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 @@ +<HTML> +<BODY> +<PRE> +<!-- Manpage converted by man2html 3.0.1 --> + + +</PRE> +<H2>DESCRIPTION</H2><PRE> + The <B>injail</B> utility returns a result which indicates the jailed status of + the current process environment. + + +</PRE> +<H2>DIAGNOSTICS</H2><PRE> + The <B>injail</B> 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. + + +</PRE> +<H2>BUGS</H2><PRE> + <B>injail</B> uses <B>kvm_getprocs(3)</B> to determine process status. Anything which + could cause a failure in either <B>kvm_open(3)</B> or <B>kvm_getprocs(3)</B> can cause + this to fail as well. There aught to be a cleaner way. + + +</PRE> +<H2>AUTHOR</H2><PRE> + James E. Quick <jq@quick.com> + + +</PRE> +<H2>SEE ALSO</H2><PRE> + <B>jailer(8)</B>, <B>jail(8)</B>, <B>kvm(3)</B> + +FreeBSD 4.6 May 28, 2002 FreeBSD 4.6 +</PRE> +<HR> +<ADDRESS> +Man(1) output converted with +<a href="http://www.oac.uci.edu/indiv/ehood/man2html.html">man2html</a> +</ADDRESS> +</BODY> +</HTML> 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 @@ +<HTML> +<BODY> +<PRE> +<!-- Manpage converted by man2html 3.0.1 --> + +</PRE> +<H2>SYNOPSIS</H2><PRE> + <B>jailer</B> <B>[</B> <I>console-file</I> <B>]</B> + + +</PRE> +<H2>DESCRIPTION</H2><PRE> + <B>jailer</B> 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: + + <B>jail</B> <B>/jails/myjail</B> <B>host</B> <B>10.0.1.1</B> <B>/bin/sh</B> <B>/etc/rc</B> + + use: + + <B>jail</B> <B>/jails/myjail</B> <B>host</B> <B>10.0.1.1</B> <B>/usr/local/sbin/jailer</B> + + + <B>jailer</B> will start the jail by running <I>/etc/rc</I> 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 <I>/etc/rc.shutdown</I>, + 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 <B>jailer</B> to restart the jail. If the jail is + not running at the time it is simply started. + + QUIT Initiates a jail shutdown. <B>jailer</B> remains running + after processing the request. + + TERM Same as <I>QUIT</I> but also quits jailer. No more pro- + cesses will be left running inside the jail. + + + +</PRE> +<H2>JAIL CONSOLE MANAGEMENT</H2><PRE> + A normal jail has no console perse, and <B>dmesg(8)</B> reads + straight from the host kernel message buffer. <B>jailer</B> + changes this to provide a virtual console for the jail. + + On jailer startup the file <I>/var/log/console</I> is created or + truncated. <I>/dev/console</I> is then hard linked to the con- + sole file. + + Along with the jailer distribution you'll find a new + <B>dmesg(8)</B> which just reads from <I>/dev/console.</I> Replace + <B>/sbin/</B><B>dmesg(8)</B> with this new executable and you're set. + + + +</PRE> +<H2>OPTIONS</H2><PRE> + console-file + Overrides the default location of the console log + file, usually <I>/var/log/console</I> + + + +</PRE> +<H2>FILES</H2><PRE> + <I>/var/log/console</I> + Virtual console file. + + + +</PRE> +<H2>BUGS</H2><PRE> + Virtual jail consoles don't work with FreeBSD 5.0 yet. + This is due to <B>devfs(8)</B> + + <B>shutdown(8)</B> doesn't work with the <I>halt</I> and <I>reboot</I> scripts. + + + +</PRE> +<H2>AUTHOR</H2><PRE> + Nate Nielsen <nielsen@memberwebs.com> + + + +</PRE> +<H2>SEE ALSO</H2><PRE> + <B>jail(8)</B>, <B>halt(8)</B>, <B>reboot(8)</B>, <B>dmesg(8)</B> + + + +Version 1.2 May 2002 <B>JAILER(8)</B> +</PRE> +<HR> +<ADDRESS> +Man(1) output converted with +<a href="http://www.oac.uci.edu/indiv/ehood/man2html.html">man2html</a> +</ADDRESS> +</BODY> +</HTML> 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 <jq@quick.com>
++
++.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 <kvm.h>
++#include <sys/param.h>
++#include <paths.h>
++#include <limits.h>
++#include <sys/types.h>
++#include <sys/user.h>
++#include <sys/sysctl.h>
++#include <sys/file.h>
++#include <stdio.h>
++
++#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 <stdio.h>
++
++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: <nielsen@memberwebs.com> +# + +# +# '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: <nielsen@memberwebs.com> +# + +# +# '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: <nielsen@memberwebs.com> +// +// CHANGES +// 1.1 +// Initial implementation +*/ + +#define SYSLOG_NAMES + +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <stdio.h> +#include <syslog.h> +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdarg.h> + + +#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 <jq@quick.com> +.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 <jq@quick.com> +// 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: <nielsen@memberwebs.com> +// +// 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 <kvm.h> +#include <sys/param.h> +#include <paths.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/user.h> +#include <sys/sysctl.h> +#include <sys/file.h> +#include <stdio.h> + +#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 <jq@quick.com> +// +// 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: <nielsen@memberwebs.com> +// +// 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 <stdio.h> + +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 <nielsen@memberwebs.com> + +.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: <nielsen@memberwebs.com> +// +// 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 <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/param.h> +#include <sys/user.h> +#include <sys/sysctl.h> +#include <sys/file.h> + +#include <kvm.h> +#include <paths.h> +#include <signal.h> +#include <stdio.h> +#include <syslog.h> +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdarg.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> + +#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 |