Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 1 | Date: Tue, 06 Feb 2007 16:06:58 -0500 |
| 2 | From: Steve Grubb <sgrubb@redhat.com> |
| 3 | Subject: Re: bash and linux audit |
| 4 | To: chet.ramey@case.edu |
| 5 | Organization: Red Hat |
| 6 | |
| 7 | OK, I released audit 1.4 Sunday which has the logging function for user |
| 8 | commands. It produces audit events like this: |
| 9 | |
| 10 | type=USER_CMD msg=audit(01/30/2007 18:23:45.793:143) : user pid=22862 uid=root |
| 11 | auid=root subj=system_u:system_r:unconfined_t:s0-s0:c0.c1023 |
| 12 | msg='cwd=/root/test dir cmd=ls -l (terminal=tty1 res=success)' |
| 13 | |
| 14 | diff -urp bash-3.2.orig/config-bot.h bash-3.2/config-bot.h |
| 15 | --- bash-3.2.orig/config-bot.h 2007-01-03 09:01:05.000000000 -0500 |
| 16 | +++ bash-3.2/config-bot.h 2007-01-20 11:59:23.000000000 -0500 |
| 17 | @@ -97,6 +97,11 @@ |
| 18 | # define RESTRICTED_SHELL_NAME "rbash" |
| 19 | #endif |
| 20 | |
| 21 | +/* If the shell is called by this name, it will become audited. */ |
| 22 | +#if defined (AUDIT_SHELL) |
| 23 | +# define AUDIT_SHELL_NAME "aubash" |
| 24 | +#endif |
| 25 | + |
| 26 | /***********************************************************/ |
| 27 | /* Make sure feature defines have necessary prerequisites. */ |
| 28 | /***********************************************************/ |
| 29 | diff -urp bash-3.2.orig/config.h.in bash-3.2/config.h.in |
| 30 | --- bash-3.2.orig/config.h.in 2007-01-03 09:01:05.000000000 -0500 |
| 31 | +++ bash-3.2/config.h.in 2007-01-20 11:59:23.000000000 -0500 |
| 32 | @@ -81,6 +81,11 @@ |
| 33 | flag. */ |
| 34 | #undef RESTRICTED_SHELL |
| 35 | |
| 36 | +/* Define AUDIT_SHELL if you want the generated shell to audit all |
| 37 | + actions performed by root account. The shell thus generated can become |
| 38 | + audited by being run with the name "aubash". */ |
| 39 | +#undef AUDIT_SHELL |
| 40 | + |
| 41 | /* Define DISABLED_BUILTINS if you want "builtin foo" to always run the |
| 42 | shell builtin "foo", even if it has been disabled with "enable -n foo". */ |
| 43 | #undef DISABLED_BUILTINS |
| 44 | diff -urp bash-3.2.orig/configure.in bash-3.2/configure.in |
| 45 | --- bash-3.2.orig/configure.in 2007-01-03 09:01:05.000000000 -0500 |
| 46 | +++ bash-3.2/configure.in 2007-01-20 11:59:23.000000000 -0500 |
| 47 | @@ -162,6 +162,7 @@ opt_history=yes |
| 48 | opt_bang_history=yes |
| 49 | opt_dirstack=yes |
| 50 | opt_restricted=yes |
| 51 | +opt_audit=yes |
| 52 | opt_process_subst=yes |
| 53 | opt_prompt_decoding=yes |
| 54 | opt_select=yes |
| 55 | @@ -195,8 +196,8 @@ dnl a minimal configuration turns everyt |
| 56 | dnl added individually |
| 57 | if test $opt_minimal_config = yes; then |
| 58 | opt_job_control=no opt_alias=no opt_readline=no |
| 59 | - opt_history=no opt_bang_history=no opt_dirstack=no |
| 60 | - opt_restricted=no opt_process_subst=no opt_prompt_decoding=no |
| 61 | + opt_history=no opt_bang_history=no opt_dirstack=no opt_restricted=no |
| 62 | + opt_audit=no opt_process_subst=no opt_prompt_decoding=no |
| 63 | opt_select=no opt_help=no opt_array_variables=no opt_dparen_arith=no |
| 64 | opt_brace_expansion=no opt_disabled_builtins=no opt_command_timing=no |
| 65 | opt_extended_glob=no opt_cond_command=no opt_arith_for_command=no |
| 66 | @@ -227,6 +228,7 @@ AC_ARG_ENABLE(progcomp, AC_HELP_STRING([ |
| 67 | AC_ARG_ENABLE(prompt-string-decoding, AC_HELP_STRING([--enable-prompt-string-decoding], [turn on escape character decoding in prompts]), opt_prompt_decoding=$enableval) |
| 68 | AC_ARG_ENABLE(readline, AC_HELP_STRING([--enable-readline], [turn on command line editing]), opt_readline=$enableval) |
| 69 | AC_ARG_ENABLE(restricted, AC_HELP_STRING([--enable-restricted], [enable a restricted shell]), opt_restricted=$enableval) |
| 70 | +AC_ARG_ENABLE(audit, AC_HELP_STRING([--enable-audit], [enable an audited shell]), opt_audit=$enableval) |
| 71 | AC_ARG_ENABLE(select, AC_HELP_STRING([--enable-select], [include select command]), opt_select=$enableval) |
| 72 | AC_ARG_ENABLE(separate-helpfiles, AC_HELP_STRING([--enable-separate-helpfiles], [use external files for help builtin documentation]), opt_separate_help=$enableval) |
| 73 | 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) |
| 74 | @@ -254,6 +256,10 @@ fi |
| 75 | if test $opt_restricted = yes; then |
| 76 | AC_DEFINE(RESTRICTED_SHELL) |
| 77 | fi |
| 78 | +if test $opt_audit = yes; then |
| 79 | +AC_DEFINE(AUDIT_SHELL) |
| 80 | +AUDIT_LIB='-laudit' |
| 81 | +fi |
| 82 | if test $opt_process_subst = yes; then |
| 83 | AC_DEFINE(PROCESS_SUBSTITUTION) |
| 84 | fi |
| 85 | @@ -355,6 +361,8 @@ AC_SUBST(HELPDIRDEFINE) |
| 86 | AC_SUBST(HELPINSTALL) |
| 87 | AC_SUBST(HELPSTRINGS) |
| 88 | |
| 89 | +AC_SUBST(AUDIT_LIB) |
| 90 | + |
| 91 | echo "" |
| 92 | echo "Beginning configuration for bash-$BASHVERS-$RELSTATUS for ${host_cpu}-${host_vendor}-${host_os}" |
| 93 | echo "" |
| 94 | diff -urp bash-3.2.orig/doc/bash.1 bash-3.2/doc/bash.1 |
| 95 | --- bash-3.2.orig/doc/bash.1 2007-01-03 09:01:05.000000000 -0500 |
| 96 | +++ bash-3.2/doc/bash.1 2007-01-20 11:59:23.000000000 -0500 |
| 97 | @@ -155,6 +155,12 @@ single-character options to be recognize |
| 98 | .PP |
| 99 | .PD 0 |
| 100 | .TP |
| 101 | +.B \-\-audit |
| 102 | +The shell logs all commands run by the root user (see |
| 103 | +.SM |
| 104 | +.B "AUDIT SHELL" |
| 105 | +below). |
| 106 | +.TP |
| 107 | .B \-\-debugger |
| 108 | Arrange for the debugger profile to be executed before the shell |
| 109 | starts. |
| 110 | @@ -8770,6 +8776,17 @@ turns off any restrictions in the shell |
| 111 | script. |
| 112 | .\" end of rbash.1 |
| 113 | .if \n(zY=1 .ig zY |
| 114 | +.SH "AUDIT SHELL" |
| 115 | +.zY |
| 116 | +.PP |
| 117 | +If |
| 118 | +.B bash |
| 119 | +is started with the name |
| 120 | +.BR aubash , |
| 121 | +or the |
| 122 | +.B \-\-audit |
| 123 | +option is supplied at invocation, the shell logs all commands issued by the root user to the audit system. |
| 124 | +.if \n(zY=1 .ig zY |
| 125 | .SH "SEE ALSO" |
| 126 | .PD 0 |
| 127 | .TP |
| 128 | diff -urp bash-3.2.orig/eval.c bash-3.2/eval.c |
| 129 | --- bash-3.2.orig/eval.c 2007-01-03 09:01:06.000000000 -0500 |
| 130 | +++ bash-3.2/eval.c 2007-01-20 11:59:23.000000000 -0500 |
| 131 | @@ -45,6 +45,11 @@ |
| 132 | # include "bashhist.h" |
| 133 | #endif |
| 134 | |
| 135 | +#if defined (AUDIT_SHELL) |
| 136 | +# include <libaudit.h> |
| 137 | +# include <errno.h> |
| 138 | +#endif |
| 139 | + |
| 140 | extern int EOF_reached; |
| 141 | extern int indirection_level; |
| 142 | extern int posixly_correct; |
| 143 | @@ -58,6 +63,38 @@ extern int rpm_requires; |
| 144 | static void send_pwd_to_eterm __P((void)); |
| 145 | static sighandler alrm_catcher __P((int)); |
| 146 | |
| 147 | +#if defined (AUDIT_SHELL) |
| 148 | +static int audit_fd = -1; |
| 149 | + |
| 150 | +static int |
| 151 | +audit_start () |
| 152 | +{ |
| 153 | + audit_fd = audit_open (); |
| 154 | + if (audit_fd < 0) |
| 155 | + return -1; |
| 156 | + else |
| 157 | + return 0; |
| 158 | +} |
| 159 | + |
| 160 | +static int |
| 161 | +audit (cmd, result) |
| 162 | + char *cmd; |
| 163 | + int result; |
| 164 | +{ |
| 165 | + int rc; |
| 166 | + |
| 167 | + if (audit_fd < 0) |
| 168 | + return 0; |
| 169 | + |
| 170 | + rc = audit_log_user_command (audit_fd, AUDIT_USER_CMD, cmd, |
| 171 | + NULL, !result); |
| 172 | + close (audit_fd); |
| 173 | + audit_fd = -1; |
| 174 | + return rc; |
| 175 | +} |
| 176 | +#endif |
| 177 | + |
| 178 | + |
| 179 | /* Read and execute commands until EOF is reached. This assumes that |
| 180 | the input source has already been initialized. */ |
| 181 | int |
| 182 | @@ -145,7 +182,25 @@ reader_loop () |
| 183 | |
| 184 | executing = 1; |
| 185 | stdin_redir = 0; |
| 186 | +#if defined (AUDIT_SHELL) |
| 187 | + if (audited && interactive_shell && getuid () == 0) |
| 188 | + { |
| 189 | + if (audit_start () < 0) |
| 190 | + { |
| 191 | + if (errno != EINVAL && errno != EPROTONOSUPPORT && |
| 192 | + errno != EAFNOSUPPORT) |
| 193 | + return EXECUTION_FAILURE; |
| 194 | + } |
| 195 | + } |
| 196 | +#endif |
| 197 | + |
| 198 | execute_command (current_command); |
| 199 | +#if defined (AUDIT_SHELL) |
| 200 | + { |
| 201 | + extern char *shell_input_line; |
| 202 | + audit (shell_input_line, last_command_exit_value); |
| 203 | + } |
| 204 | +#endif |
| 205 | |
| 206 | exec_done: |
| 207 | QUIT; |
| 208 | diff -urp bash-3.2.orig/externs.h bash-3.2/externs.h |
| 209 | --- bash-3.2.orig/externs.h 2007-01-03 09:01:06.000000000 -0500 |
| 210 | +++ bash-3.2/externs.h 2007-01-20 12:05:00.000000000 -0500 |
| 211 | @@ -77,6 +77,10 @@ extern int shell_is_restricted __P((char |
| 212 | extern int maybe_make_restricted __P((char *)); |
| 213 | #endif |
| 214 | |
| 215 | +#if defined (AUDIT_SHELL) |
| 216 | +extern int maybe_make_audited __P((char *)); |
| 217 | +#endif |
| 218 | + |
| 219 | extern void unset_bash_input __P((int)); |
| 220 | extern void get_current_user_info __P((void)); |
| 221 | |
| 222 | diff -urp bash-3.2.orig/flags.c bash-3.2/flags.c |
| 223 | --- bash-3.2.orig/flags.c 2007-01-03 09:01:06.000000000 -0500 |
| 224 | +++ bash-3.2/flags.c 2007-01-20 11:59:23.000000000 -0500 |
| 225 | @@ -142,6 +142,12 @@ int restricted = 0; /* currently restri |
| 226 | int restricted_shell = 0; /* shell was started in restricted mode. */ |
| 227 | #endif /* RESTRICTED_SHELL */ |
| 228 | |
| 229 | +#if defined (AUDIT_SHELL) |
| 230 | +/* Non-zero means that this shell is audited. An audited shell records |
| 231 | + each command that the root user executes. */ |
| 232 | +int audited = 0; /* shell was started in audit mode. */ |
| 233 | +#endif /* AUDIT_SHELL */ |
| 234 | + |
| 235 | /* Non-zero means that this shell is running in `privileged' mode. This |
| 236 | is required if the shell is to run setuid. If the `-p' option is |
| 237 | not supplied at startup, and the real and effective uids or gids |
| 238 | diff -urp bash-3.2.orig/flags.h bash-3.2/flags.h |
| 239 | --- bash-3.2.orig/flags.h 2007-01-03 09:01:06.000000000 -0500 |
| 240 | +++ bash-3.2/flags.h 2007-01-20 11:59:23.000000000 -0500 |
| 241 | @@ -66,6 +66,10 @@ extern int restricted; |
| 242 | extern int restricted_shell; |
| 243 | #endif /* RESTRICTED_SHELL */ |
| 244 | |
| 245 | +#if defined (AUDIT_SHELL) |
| 246 | +extern int audited; |
| 247 | +#endif /* AUDIT_SHELL */ |
| 248 | + |
| 249 | extern int *find_flag __P((int)); |
| 250 | extern int change_flag __P((int, int)); |
| 251 | extern char *which_set_flags __P((void)); |
| 252 | Only in bash-3.2: .made |
| 253 | diff -urp bash-3.2.orig/Makefile.in bash-3.2/Makefile.in |
| 254 | --- bash-3.2.orig/Makefile.in 2007-01-03 09:01:06.000000000 -0500 |
| 255 | +++ bash-3.2/Makefile.in 2007-01-20 11:59:23.000000000 -0500 |
| 256 | @@ -366,6 +366,8 @@ MALLOC_LIBRARY = @MALLOC_LIBRARY@ |
| 257 | MALLOC_LDFLAGS = @MALLOC_LDFLAGS@ |
| 258 | MALLOC_DEP = @MALLOC_DEP@ |
| 259 | |
| 260 | +AUDIT_LIB = @AUDIT_LIB@ |
| 261 | + |
| 262 | ALLOC_HEADERS = $(ALLOC_LIBSRC)/getpagesize.h $(ALLOC_LIBSRC)/shmalloc.h \ |
| 263 | $(ALLOC_LIBSRC)/imalloc.h $(ALLOC_LIBSRC)/mstats.h \ |
| 264 | $(ALLOC_LIBSRC)/table.h $(ALLOC_LIBSRC)/watch.h |
| 265 | @@ -386,7 +388,7 @@ BASHINCFILES = $(BASHINCDIR)/posixstat. |
| 266 | $(BASHINCDIR)/ocache.h |
| 267 | |
| 268 | LIBRARIES = $(SHLIB_LIB) $(READLINE_LIB) $(HISTORY_LIB) $(TERMCAP_LIB) $(GLOB_LIB) \ |
| 269 | - $(TILDE_LIB) $(MALLOC_LIB) $(INTL_LIB) $(LOCAL_LIBS) |
| 270 | + $(TILDE_LIB) $(MALLOC_LIB) $(INTL_LIB) $(LOCAL_LIBS) $(AUDIT_LIB) |
| 271 | |
| 272 | LIBDEP = $(SHLIB_DEP) $(INTL_DEP) $(READLINE_DEP) $(HISTORY_DEP) $(TERMCAP_DEP) $(GLOB_DEP) \ |
| 273 | $(TILDE_DEP) $(MALLOC_DEP) |
| 274 | diff -urp bash-3.2.orig/parse.y bash-3.2/parse.y |
| 275 | --- bash-3.2.orig/parse.y 2007-01-03 09:01:06.000000000 -0500 |
| 276 | +++ bash-3.2/parse.y 2007-01-20 11:59:23.000000000 -0500 |
| 277 | @@ -258,7 +258,7 @@ int need_here_doc; |
| 278 | |
| 279 | /* Where shell input comes from. History expansion is performed on each |
| 280 | line when the shell is interactive. */ |
| 281 | -static char *shell_input_line = (char *)NULL; |
| 282 | +char *shell_input_line = (char *)NULL; |
| 283 | static int shell_input_line_index; |
| 284 | static int shell_input_line_size; /* Amount allocated for shell_input_line. */ |
| 285 | static int shell_input_line_len; /* strlen (shell_input_line) */ |
| 286 | diff -urp bash-3.2.orig/shell.c bash-3.2/shell.c |
| 287 | --- bash-3.2.orig/shell.c 2007-01-03 09:01:06.000000000 -0500 |
| 288 | +++ bash-3.2/shell.c 2007-01-20 12:04:23.000000000 -0500 |
| 289 | @@ -240,6 +240,9 @@ struct { |
| 290 | #if defined (RESTRICTED_SHELL) |
| 291 | { "restricted", Int, &restricted, (char **)0x0 }, |
| 292 | #endif |
| 293 | +#if defined (AUDIT_SHELL) |
| 294 | + { "audit", Int, &audited, (char **)0x0 }, |
| 295 | +#endif |
| 296 | { "verbose", Int, &echo_input_at_read, (char **)0x0 }, |
| 297 | { "version", Int, &do_version, (char **)0x0 }, |
| 298 | { "wordexp", Int, &wordexp_only, (char **)0x0 }, |
| 299 | @@ -644,6 +647,10 @@ main (argc, argv, env) |
| 300 | maybe_make_restricted (shell_name); |
| 301 | #endif /* RESTRICTED_SHELL */ |
| 302 | |
| 303 | +#if defined (AUDIT_SHELL) |
| 304 | + maybe_make_audited (shell_name); |
| 305 | +#endif |
| 306 | + |
| 307 | if (wordexp_only) |
| 308 | { |
| 309 | startup_state = 3; |
| 310 | @@ -1143,6 +1150,29 @@ maybe_make_restricted (name) |
| 311 | } |
| 312 | #endif /* RESTRICTED_SHELL */ |
| 313 | |
| 314 | +#if defined (AUDIT_SHELL) |
| 315 | +/* Perhaps make this shell an `audited' one, based on NAME. If the |
| 316 | + basename of NAME is "aubash", then this shell is audited. The |
| 317 | + name of the audited shell is a configurable option, see config.h. |
| 318 | + In an audited shell, all actions performed by root will be logged |
| 319 | + to the audit system. |
| 320 | + Do this also if `audited' is already set to 1 maybe the shell was |
| 321 | + started with --audit. */ |
| 322 | +int |
| 323 | +maybe_make_audited (name) |
| 324 | + char *name; |
| 325 | +{ |
| 326 | + char *temp; |
| 327 | + |
| 328 | + temp = base_pathname (name); |
| 329 | + if (*temp == '-') |
| 330 | + temp++; |
| 331 | + if (audited || (STREQ (temp, AUDIT_SHELL_NAME))) |
| 332 | + audited = 1; |
| 333 | + return (audited); |
| 334 | +} |
| 335 | +#endif /* AUDIT_SHELL */ |
| 336 | + |
| 337 | /* Fetch the current set of uids and gids and return 1 if we're running |
| 338 | setuid or setgid. */ |
| 339 | static int |