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