summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2010-04-05 09:48:26 -0700
committerStephen Hemminger <stephen.hemminger@vyatta.com>2010-04-05 09:48:26 -0700
commitc6a8e270ab694c2291216b8c554c2f5f9dcf0fd0 (patch)
treed964a27ef6a135377ef09358e9414af5ac747ca4
parent8c105a156601216de19ff17fca1ab34fe798f1c5 (diff)
downloadvyatta-bash-c6a8e270ab694c2291216b8c554c2f5f9dcf0fd0.tar.gz
vyatta-bash-c6a8e270ab694c2291216b8c554c2f5f9dcf0fd0.zip
Add auditing support to bash
This is based on earlier (unaccepted) patch to add auditing support which wasd done by Steve Grubb at Redhat. This patch depends on audit 1.4 to provide a logging function. The resulting audit message looks like this: time->Tue Jan 30 18:23:45 2007 type=USER_CMD msg=audit(1170199425.793:143): user pid=22862 uid=0 auid=0 subj=system_u:system_r:unconfined_t:s0-s0:c0.c1023 msg='cwd=2F726F6F742F7465737420646972 cmd=6C73202D6C (terminal=tty1 res=success)' Which translates to: type=USER_CMD msg=audit(01/30/2007 18:23:45.793:143) : user pid=22862 uid=root auid=root subj=system_u:system_r:unconfined_t:s0-s0:c0.c1023 msg='cwd=/root/test dir cmd=ls -l (terminal=tty1 res=success)' This patch causes bash to log all command line arguments when the shell is started as aubash or "bash --audit". The preferred methos is to make a symlink frp, bash to aubash and then add aubash to /etc/shells. Then you can change root's shell to aubash.
-rw-r--r--Makefile.in4
-rw-r--r--config-bot.h5
-rw-r--r--config.h.in5
-rw-r--r--configure.in12
-rw-r--r--debian/control3
-rwxr-xr-xdebian/rules1
-rw-r--r--doc/bash.117
-rw-r--r--eval.c55
-rw-r--r--externs.h4
-rw-r--r--flags.c6
-rw-r--r--flags.h4
-rw-r--r--parse.y2
-rw-r--r--shell.c30
13 files changed, 143 insertions, 5 deletions
diff --git a/Makefile.in b/Makefile.in
index 28af658..79e0e9f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -359,6 +359,8 @@ MALLOC_LIBRARY = @MALLOC_LIBRARY@
MALLOC_LDFLAGS = @MALLOC_LDFLAGS@
MALLOC_DEP = @MALLOC_DEP@
+AUDIT_LIB = @AUDIT_LIB@
+
ALLOC_HEADERS = $(ALLOC_LIBSRC)/getpagesize.h $(ALLOC_LIBSRC)/shmalloc.h \
$(ALLOC_LIBSRC)/imalloc.h $(ALLOC_LIBSRC)/mstats.h \
$(ALLOC_LIBSRC)/table.h $(ALLOC_LIBSRC)/watch.h
@@ -379,7 +381,7 @@ BASHINCFILES = $(BASHINCDIR)/posixstat.h $(BASHINCDIR)/ansi_stdlib.h \
$(BASHINCDIR)/ocache.h
LIBRARIES = $(SHLIB_LIB) $(READLINE_LIB) $(HISTORY_LIB) $(TERMCAP_LIB) $(GLOB_LIB) \
- $(TILDE_LIB) $(MALLOC_LIB) $(INTL_LIB) $(LOCAL_LIBS)
+ $(TILDE_LIB) $(MALLOC_LIB) $(INTL_LIB) $(LOCAL_LIBS) $(AUDIT_LIB)
LIBDEP = $(SHLIB_DEP) $(INTL_DEP) $(READLINE_DEP) $(HISTORY_DEP) $(TERMCAP_DEP) $(GLOB_DEP) \
$(TILDE_DEP) $(MALLOC_DEP)
diff --git a/config-bot.h b/config-bot.h
index 1b8fd5d..a4f95cf 100644
--- a/config-bot.h
+++ b/config-bot.h
@@ -97,6 +97,11 @@
# define RESTRICTED_SHELL_NAME "rbash"
#endif
+/* If the shell is called by this name, it will become audited. */
+#if defined (AUDIT_SHELL)
+# define AUDIT_SHELL_NAME "aubash"
+#endif
+
/***********************************************************/
/* Make sure feature defines have necessary prerequisites. */
/***********************************************************/
diff --git a/config.h.in b/config.h.in
index 7fde761..46d281b 100644
--- a/config.h.in
+++ b/config.h.in
@@ -81,6 +81,11 @@
flag. */
#undef RESTRICTED_SHELL
+/* Define AUDIT_SHELL if you want the generated shell to audit all
+ actions performed by root account. The shell thus generated can become
+ audited by being run with the name "aubash". */
+#undef AUDIT_SHELL
+
/* Define DISABLED_BUILTINS if you want "builtin foo" to always run the
shell builtin "foo", even if it has been disabled with "enable -n foo". */
#undef DISABLED_BUILTINS
diff --git a/configure.in b/configure.in
index 182d773..c40c1bd 100644
--- a/configure.in
+++ b/configure.in
@@ -162,6 +162,7 @@ opt_history=yes
opt_bang_history=yes
opt_dirstack=yes
opt_restricted=yes
+opt_audit=yes
opt_process_subst=yes
opt_prompt_decoding=yes
opt_select=yes
@@ -195,8 +196,8 @@ dnl a minimal configuration turns everything off, but features can be
dnl added individually
if test $opt_minimal_config = yes; then
opt_job_control=no opt_alias=no opt_readline=no
- opt_history=no opt_bang_history=no opt_dirstack=no
- opt_restricted=no opt_process_subst=no opt_prompt_decoding=no
+ opt_history=no opt_bang_history=no opt_dirstack=no opt_restricted=no
+ opt_audit=no opt_process_subst=no opt_prompt_decoding=no
opt_select=no opt_help=no opt_array_variables=no opt_dparen_arith=no
opt_brace_expansion=no opt_disabled_builtins=no opt_command_timing=no
opt_extended_glob=no opt_cond_command=no opt_arith_for_command=no
@@ -227,6 +228,7 @@ AC_ARG_ENABLE(progcomp, AC_HELP_STRING([--enable-progcomp], [enable programmable
AC_ARG_ENABLE(prompt-string-decoding, AC_HELP_STRING([--enable-prompt-string-decoding], [turn on escape character decoding in prompts]), opt_prompt_decoding=$enableval)
AC_ARG_ENABLE(readline, AC_HELP_STRING([--enable-readline], [turn on command line editing]), opt_readline=$enableval)
AC_ARG_ENABLE(restricted, AC_HELP_STRING([--enable-restricted], [enable a restricted shell]), opt_restricted=$enableval)
+AC_ARG_ENABLE(audit, AC_HELP_STRING([--enable-audit], [enable an audited shell]), opt_audit=$enableval)
AC_ARG_ENABLE(select, AC_HELP_STRING([--enable-select], [include select command]), opt_select=$enableval)
AC_ARG_ENABLE(separate-helpfiles, AC_HELP_STRING([--enable-separate-helpfiles], [use external files for help builtin documentation]), opt_separate_help=$enableval)
AC_ARG_ENABLE(single-help-strings, AC_HELP_STRING([--enable-single-help-strings], [store help documentation as a single string to ease translation]), opt_single_longdoc_strings=$enableval)
@@ -254,6 +256,10 @@ fi
if test $opt_restricted = yes; then
AC_DEFINE(RESTRICTED_SHELL)
fi
+if test $opt_audit = yes; then
+AC_DEFINE(AUDIT_SHELL)
+AUDIT_LIB='-laudit'
+fi
if test $opt_process_subst = yes; then
AC_DEFINE(PROCESS_SUBSTITUTION)
fi
@@ -355,6 +361,8 @@ AC_SUBST(HELPDIRDEFINE)
AC_SUBST(HELPINSTALL)
AC_SUBST(HELPSTRINGS)
+AC_SUBST(AUDIT_LIB)
+
echo ""
echo "Beginning configuration for bash-$BASHVERS-$RELSTATUS for ${host_cpu}-${host_vendor}-${host_os}"
echo ""
diff --git a/debian/control b/debian/control
index cfc0652..8e5985d 100644
--- a/debian/control
+++ b/debian/control
@@ -3,7 +3,8 @@ Section: base
Priority: optional
Maintainer: Vyatta Package Maintainers <maintainers@vyatta.com>
Standards-Version: 3.6.2
-Build-Depends: autoconf, patch, bison, libncurses5-dev, texinfo, autotools-dev, debhelper (>= 4.1), texi2html, locales
+Build-Depends: autoconf, patch, bison, libncurses5-dev, texinfo, autotools-dev,
+ debhelper (>= 4.1), texi2html, locales, libaudit-dev
Build-Depends-Indep: tetex-bin
Package: vyatta-bash
diff --git a/debian/rules b/debian/rules
index 0935fcc..20225f2 100755
--- a/debian/rules
+++ b/debian/rules
@@ -43,6 +43,7 @@ d = debian/$(p)
conf_args = \
--with-curses \
--disable-net-redirections \
+ --enable-audit \
--enable-largefile \
--prefix=/usr \
--infodir=/usr/share/info \
diff --git a/doc/bash.1 b/doc/bash.1
index 80d51fa..f6f6649 100644
--- a/doc/bash.1
+++ b/doc/bash.1
@@ -154,6 +154,12 @@ single-character options to be recognized.
.PP
.PD 0
.TP
+.B \-\-audit
+The shell logs all commands run by the root user (see
+.SM
+.B "AUDIT SHELL"
+below).
+.TP
.B \-\-debugger
Arrange for the debugger profile to be executed before the shell
starts.
@@ -8797,6 +8803,17 @@ turns off any restrictions in the shell spawned to execute the
script.
.\" end of rbash.1
.if \n(zY=1 .ig zY
+.SH "AUDIT SHELL"
+.zY
+.PP
+If
+.B bash
+is started with the name
+.BR aubash ,
+or the
+.B \-\-audit
+option is supplied at invocation, the shell logs all commands issued by the root user to the audit system.
+.if \n(zY=1 .ig zY
.SH "SEE ALSO"
.PD 0
.TP
diff --git a/eval.c b/eval.c
index 4f4a13f..e493643 100644
--- a/eval.c
+++ b/eval.c
@@ -45,6 +45,11 @@
# include "bashhist.h"
#endif
+#if defined (AUDIT_SHELL)
+# include <libaudit.h>
+# include <errno.h>
+#endif
+
extern int EOF_reached;
extern int indirection_level;
extern int posixly_correct;
@@ -62,6 +67,38 @@ extern char *current_readline_line;
extern int current_readline_line_index;
#endif
+#if defined (AUDIT_SHELL)
+static int audit_fd = -1;
+
+static int
+audit_start ()
+{
+ audit_fd = audit_open ();
+ if (audit_fd < 0)
+ return -1;
+ else
+ return 0;
+}
+
+static int
+audit (cmd, result)
+ char *cmd;
+ int result;
+{
+ int rc;
+
+ if (audit_fd < 0)
+ return 0;
+
+ rc = audit_log_user_command (audit_fd, AUDIT_USER_CMD, cmd,
+ NULL, !result);
+ close (audit_fd);
+ audit_fd = -1;
+ return rc;
+}
+#endif
+
+
/* Read and execute commands until EOF is reached. This assumes that
the input source has already been initialized. */
int
@@ -149,7 +186,25 @@ reader_loop ()
executing = 1;
stdin_redir = 0;
+#if defined (AUDIT_SHELL)
+ if (audited && interactive_shell && getuid () == 0)
+ {
+ if (audit_start () < 0)
+ {
+ if (errno != EINVAL && errno != EPROTONOSUPPORT &&
+ errno != EAFNOSUPPORT)
+ return EXECUTION_FAILURE;
+ }
+ }
+#endif
+
execute_command (current_command);
+#if defined (AUDIT_SHELL)
+ {
+ extern char *shell_input_line;
+ audit (shell_input_line, last_command_exit_value);
+ }
+#endif
exec_done:
QUIT;
diff --git a/externs.h b/externs.h
index 094d924..e2dd09f 100644
--- a/externs.h
+++ b/externs.h
@@ -77,6 +77,10 @@ extern int shell_is_restricted __P((char *));
extern int maybe_make_restricted __P((char *));
#endif
+#if defined (AUDIT_SHELL)
+extern int maybe_make_audited __P((char *));
+#endif
+
extern void unset_bash_input __P((int));
extern void get_current_user_info __P((void));
diff --git a/flags.c b/flags.c
index 0c0868b..e50d6dc 100644
--- a/flags.c
+++ b/flags.c
@@ -142,6 +142,12 @@ int restricted = 0; /* currently restricted */
int restricted_shell = 0; /* shell was started in restricted mode. */
#endif /* RESTRICTED_SHELL */
+#if defined (AUDIT_SHELL)
+/* Non-zero means that this shell is audited. An audited shell records
+ each command that the root user executes. */
+int audited = 0; /* shell was started in audit mode. */
+#endif /* AUDIT_SHELL */
+
/* Non-zero means that this shell is running in `privileged' mode. This
is required if the shell is to run setuid. If the `-p' option is
not supplied at startup, and the real and effective uids or gids
diff --git a/flags.h b/flags.h
index f16e604..1ee63c8 100644
--- a/flags.h
+++ b/flags.h
@@ -66,6 +66,10 @@ extern int restricted;
extern int restricted_shell;
#endif /* RESTRICTED_SHELL */
+#if defined (AUDIT_SHELL)
+extern int audited;
+#endif /* AUDIT_SHELL */
+
extern int *find_flag __P((int));
extern int change_flag __P((int, int));
extern char *which_set_flags __P((void));
diff --git a/parse.y b/parse.y
index 4fe354f..a179c93 100644
--- a/parse.y
+++ b/parse.y
@@ -263,7 +263,7 @@ int need_here_doc;
/* Where shell input comes from. History expansion is performed on each
line when the shell is interactive. */
-static char *shell_input_line = (char *)NULL;
+char *shell_input_line = (char *)NULL;
static int shell_input_line_index;
static int shell_input_line_size; /* Amount allocated for shell_input_line. */
static int shell_input_line_len; /* strlen (shell_input_line) */
diff --git a/shell.c b/shell.c
index b8dcf32..b417d24 100644
--- a/shell.c
+++ b/shell.c
@@ -236,6 +236,9 @@ struct {
#if defined (RESTRICTED_SHELL)
{ "restricted", Int, &restricted, (char **)0x0 },
#endif
+#if defined (AUDIT_SHELL)
+ { "audit", Int, &audited, (char **)0x0 },
+#endif
{ "verbose", Int, &echo_input_at_read, (char **)0x0 },
{ "version", Int, &do_version, (char **)0x0 },
{ "wordexp", Int, &wordexp_only, (char **)0x0 },
@@ -633,6 +636,10 @@ main (argc, argv, env)
maybe_make_restricted (shell_name);
#endif /* RESTRICTED_SHELL */
+#if defined (AUDIT_SHELL)
+ maybe_make_audited (shell_name);
+#endif
+
if (wordexp_only)
{
startup_state = 3;
@@ -1132,6 +1139,29 @@ maybe_make_restricted (name)
}
#endif /* RESTRICTED_SHELL */
+#if defined (AUDIT_SHELL)
+/* Perhaps make this shell an `audited' one, based on NAME. If the
+ basename of NAME is "aubash", then this shell is audited. The
+ name of the audited shell is a configurable option, see config.h.
+ In an audited shell, all actions performed by root will be logged
+ to the audit system.
+ Do this also if `audited' is already set to 1 maybe the shell was
+ started with --audit. */
+int
+maybe_make_audited (name)
+ char *name;
+{
+ char *temp;
+
+ temp = base_pathname (name);
+ if (*temp == '-')
+ temp++;
+ if (audited || (STREQ (temp, AUDIT_SHELL_NAME)))
+ audited = 1;
+ return (audited);
+}
+#endif /* AUDIT_SHELL */
+
/* Fetch the current set of uids and gids and return 1 if we're running
setuid or setgid. */
static int