1#!${PERLPATH} 2#$Id: sudoshell-in,v 1.9 2004/11/22 16:09:05 hbo Exp $ 3 4use Fcntl qw(O_RDWR O_WRONLY); 5use POSIX qw(pause); 6use strict; 7use warnings; 8use Getopt::Long; 9use lib ${SSLIBDIR}; 10use Sudoscript; 11 12my $ss=Sudoscript->new(); 13exit if (! defined $ss); 14 15my ($user,$newenv); 16GetOptions( 17 "user:s" => \$user, 18 "" => \$newenv, 19 ); 20 21my $GREP = $ss->GREP(); 22my $SUDO=$ss->SUDO(); 23my $PS=$ss->PS(); 24my $SCRIPT=$ss->SCRIPT(); 25my $INITSCR=$ss->INITSCR(); 26 27 28# Check to see if sudoscriptd is running. Offer to start it if not 29$ss->check_ssd(); 30 31 32# Get our current ID's pwent 33my ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire) =getpwuid($>) 34 or die "no passwd entry for current user: $>\n"; 35 36# Check our -u parameter. 37if ($user){ 38 39 # Get the UID of the -u user and compare it to ours. 40 ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire) =getpwnam($user) 41 or die "no passwd entry for user: $user\n"; 42 43 if ($uid != $>){ # We have not become the requested user yet 44 # Call sudo to give us the right identity. 45 my $reexec="$SUDO -u $user $0 -u $user"; 46 $reexec .= " -" if ($newenv); 47 exec $reexec; 48 } 49 # Otherwise, check if we are root. 50} elsif ($>){ # No -u and not run as root. Try sudo 51 my $reexec= "$SUDO $0"; 52 $reexec .= " -" if ($newenv); 53 exec $reexec; 54} 55 56# We are either root or the -u user here forward 57 58# Check the user's shell 59 60$shell=$ENV{SHELL} if ($ENV{SHELL}); # Environment overrides pwent (obtained above) 61 62# Don't take their word for it. 63# Get the list of shells in /etc/shells and turn them into a single regular expression 64open SHELLS, "/etc/shells" or die "Can't open /etc/shells $!\n"; 65my $shellsre=join "|", map {chomp;s~/~\\\/~g;$_} (<SHELLS>); 66close SHELLS; 67 68if ($shell!~/$shellsre/){ 69 print "Your shell ($shell) isn't in /etc/shells! Exiting.\n"; 70 exit; 71} 72 73# Get the name we came from, if available. 74# (SUDO_UID could be blank, if root ran us to start with. In that 75# case we get the name from the first getpwuid above.) 76($name) = getpwuid $ENV{SUDO_UID} if ($ENV{SUDO_UID}); 77 78# Implement the "-" parameter. 79if ($newenv){ 80 my ($n,$p,$u,$g,$q,$c,$gc,$home,$sh) = getpwuid $>; 81 $ENV{HOME} = $home if ($home); 82 $ENV{SHELL}= $sh if ($sh and $sh =~ /$shellsre/); 83} 84 85# Open the master daemon's front-end FIFO if it exists 86# (This is why we need rwx perms for group to $fifodir.) 87my $rundir="/var/run/sudoscript"; 88my $fifo="$rundir/rendezvous"; 89 90if (-p $fifo){ 91 sysopen (FIFO,$fifo,O_WRONLY) or die $!; 92 # Unbuffer it 93 my $stdout=select FIFO; 94 $|=1; 95 select $stdout; 96 97 $SIG{WINCH}=sub{return}; # Logger will signal us 98 99 # Our handshake with sudoscriptd will differ based on whether we are running as 100 # root or an unprivileged user. 101 my $handshake; 102 if ($user){ 103 $handshake="$name $$ $user\n"; # $name is SUDO_USER or root. $user is non-root user we have become 104 } else { 105 $handshake="$name $$\n"; 106 } 107 # Say HELO to sudoscriptd 108 print FIFO "HELO $handshake\n"; 109 110 # Wait for the logger to be ready 111 pause; 112 113 # We have been awakened, prepare to script(1) to the new FIFO 114 # close te old FIFO first 115 close FIFO; 116 117 # Session FIFO name differs based on whether we are running as 118 # root or an unprivileged user. 119 my $fifo2; 120 if ($user){ 121 $fifo2=$rundir."/ssd.${name}_${user}_$$/$name$$.fifo"; 122 } else { 123 $fifo2=$rundir."/ssd.${name}_root_$$/$name$$.fifo"; 124 } 125 126 # Here we go 127 my $script=$ss->SCRIPT(); 128 129 system "$script $fifo2"; 130 131 # script(1) session has finished 132 # Reopen the old fifo to let the master know we are done. 133 sysopen (FIFO,$fifo,O_WRONLY) or die $!; 134 135 # Say GDBY, dick 136 print FIFO "GDBY $handshake\n"; 137 close FIFO; 138 139 # all done. 140 exit; 141} else { # Problem with the FIFO. (no -p $fifo) 142 print "The logging FIFO doesn't exist. Can't run shell!\n"; 143} 144 145 146=pod 147 148=head1 NAME 149 150 sudoshell, ss - Run a shell with logging 151 152=head1 SYNOPSIS 153 154sudoshell|ss [-] [-u|--user I<username>] 155 156=head1 VERSION 157 158This manpage documents version ${VERSION} of sudoshell. 159 160=head1 DESCRIPTION 161 162I<sudoshell> runs the I<script> command with a fifo as the 163typescript. Used in conjunction with L<sudoscriptd(8)> and L<sudo(8)>, it 164provides a way to maintain the sudo audit trail while running a shell. 165 166=head1 README 167 168I<sudo> is a tool used for running programs with privileges other than those 169normally possessed by the user. Often, the privileges are those of the I<root> account, 170but they could as well be those of any other user. One of I<sudo>'s 171major benefits is the audit trail it provides, as it logs each 172invocation with the command name, its arguments and the user who ran 173it. Because this audit trail is lost if a user runs a shell (e.g. bash 174or csh) with sudo, many sites restrict sudo to not allow such 175usage. Since this can cause problems, (see L<SUDO AND SHELLS>) many 176users prefer to retain the root password, even if it means forgoing 177support. This outcome also results in a loss of the audit trail, while 178increasing the chances that an unmanaged system will become a support 179problem later. 180 181Sudoshell is a small Perl script that works in conjunction with a 182logging daemon (see L<sudoscriptd(8)>) to log all activity within a 183shell. It uses the unix L<script(1)> command to create the log. Once 184invoked, all console commands and output are logged to a fifo. The 185logging daemon reads from this fifo and manages log files to store the 186data produced. The logs are rotated to ensure that they do not 187overflow the disk space on the logging partition. 188 189When started, I<sudoshell> checks to see if L<sudoscriptd(8)> is 190running and offers to start it if it is not. (It does this with sudo, 191so you need to have sudo root access to perform this step. See 192CONFIGURATION below) Sudoshell then checks to see if it has been run 193as the correct user (either root or some other user with the -u 194switch. See below.) via 'sudo sudoshell' or otherwise. If not, it 195reinvokes itself using sudo. The script then checks the user's 196shell. If the SHELL environment variable is set, I<sudoshell> uses 197that. If not, the shell entry from the passwd file is used. If the 198value thus obtained doesn't match one of the shells listed in 199/etc/shells, sudoshell refuses to run. Finally, I<sudoshell> execs 200script(1), pointing the output to a logging FIFO maintained by 201L<sudoscriptd(8)>, which gives the user a shell as the desired user. 202 203=head1 CONFIGURATION 204 205I<sudoshell> uses L<sudo(8)> to perform all its authentication and 206privilege escalation. The I<sudoshell> user must therefore be in the 207I<sudoers> file (See L<sudoers(5)>.) with an entry that allows 208running I<sudoshell> as the desired user. See the SUDOCONFIG file in 209the distribution for details. (On Linux, this will be in 210/usr/share/doc/sudoscript-VERSION. Everywhere else, it's in 211/usr/local/doc/sudoscript-VERSION.) 212 213=head1 SWITCHES 214 215=over 4 216 217=item - 218 219Like 'su -'. This switch will load the environment of the user you become, 220rather than retaining yours. 221 222 223=item -u <user> 224 225If this switch is given 226along with a username, I<sudoshell> will ask I<sudo> to give the ss 227user the identity of the user named with the -u switch. If no -u 228switch is given, I<sudoshell> will ask for a root shell. 229 230Example: 231 232sudoshell -u oracle 233 234The idea of running shells as users other than root came from Donny Jekels. 235 236=back 237 238=head1 SUDO AND SHELLS 239 240 241Most root tasks can be accomplished with sudo without running a 242shell. However certain tasks, such as running privileged commands in a 243pipeline, can be more difficult using sudo. Since sudo sometimes 244prompts for a password (depending on how long ago the user last 245authenticated) you can run into quirky situations like this: 246 247 hbo@egbok|509> sudo ls | sudo more 248 Password:Password:(enter password) 249 (enter password) 250 #sudoshell# 251 CVS 252 sudoscriptd 253 sudoscriptd~ 254 sudoshell 255 sudoshell~ 256 hbo@egbok|510> 257 258In this case we get two password prompts, right on top of one 259another. We enter the password for the first prompt, and sudo waits 260for the next one. Since the prompt is on the preceding line, this can 261be very confusing. 262 263Another place sudo has difficulty is with I/O redirection: 264 265 hbo@egbok|511 > ls -l /tmp/foo 266 -r--r--r-- 1 root other 1464 Mar 25 13:10 /tmp/foo 267 hbo@egbok|512 > sudo ls >>/tmp/foo 268 bash: /tmp/foo: Permission denied 269 hbo@egbok|513 > sudo ls | sudo cat >>/tmp/foo 270 bash: /tmp/foo: Permission denied 271 272But this works: 273 274 hbo@egbok|514 > sudo ls | sudo tee -a /tmp/foo >/dev/null 275 276It's not very intuitive, however. 277 278The problem occurs because the shell implements I/O redirection 279before it invokes the command, which is sudo, NOT ls. 280 281Globbing has problems for the same reason. But in this case, there's 282no good workaround, short of letting the user run a shell: 283 284 285 hbo@egbok|515 > mkdir fff 286 hbo@egbok|516 > chmod 700 fff 287 hbo@egbok|517 > touch fff/foo 288 hbo@egbok|518 > sudo chown root fff 289 Password: 290 hbo@egbok|519 > cd fff 291 bash: cd: fff: Permission denied 292 hbo@egbok|520 > sudo cd fff 293 sudo: cd: command not found 294 hbo@egbok|521 > sudo rm fff/* 295 rm: cannot remove `fff/*': No such file or directory 296 297The cd fails because cd is a bash builtin, and sudo doesn't know anything 298about it. The "globbing" fails because the shell tries to expand the 299wildcard before executing the command, which is sudo, not rm. 300 301=head1 BUGS 302 303Please let me know if you find any. 304 305=head1 SEE ALSO 306 307sudoscript(8) 308 309sudoscriptd(8) 310 311Sudoscript(3pm) 312 313sudo(8) 314 315sudoers(5) 316 317=head1 PREREQUISITES 318 319sudo - L<http://www.courtesan.com/sudo/index.html> 320 321=head1 OSNAMES 322 323C<Solaris> 324 325C<Linux> 326 327C<OpenBSD> 328 329C<FreeBSD> 330 331C<HP-UX> 332 333=head1 SCRIPT CATEGORIES 334 335UNIX/System_administration 336 337=head1 CONTRIBUTORS 338 339The following people offered helpful advice and/or code: 340 341 Dan Rich (drich@emplNOoyeeSPAMs.org) 342 Alex Griffiths (dag@unifiedNOcomputingSPAM.com) 343 Bruce Gray (bruce.gray@aNOcSPAMm.org) 344 Chan Wilson (cwilson@coNrOp.sSgPi.cAoMm> 345 Tommy Smith (tsNmOith@eSaPtAeMl.net) 346 Donny Jekels (donny@jNOeSkPeAlMs.com 347 348=head1 AUTHOR 349 350Howard Owen, E<lt>hbo@egbok.comE<gt> 351 352=head1 COPYRIGHT AND LICENSE 353 354Copyright 2002,2003 by Howard Owen 355 356sudoscript is free software; you can redistribute it and/or modify 357it under the same terms as Perl itself. 358 359=cut 360 361