diff options
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | config-bot.h | 5 | ||||
-rw-r--r-- | config.h.in | 5 | ||||
-rw-r--r-- | configure.in | 12 | ||||
-rw-r--r-- | debian/control | 3 | ||||
-rwxr-xr-x | debian/rules | 1 | ||||
-rw-r--r-- | doc/bash.1 | 17 | ||||
-rw-r--r-- | eval.c | 55 | ||||
-rw-r--r-- | externs.h | 4 | ||||
-rw-r--r-- | flags.c | 6 | ||||
-rw-r--r-- | flags.h | 4 | ||||
-rw-r--r-- | parse.y | 2 | ||||
-rw-r--r-- | shell.c | 30 |
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 \ @@ -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 @@ -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; @@ -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)); @@ -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 @@ -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)); @@ -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) */ @@ -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 |