|
|
(view this code in a separate window)
#!/usr/bin/suidperl
#
# Copyright 2001, Bri Hatch
# Released under the GPL
#
# rcspasswd - A program to front-end the passwd command with rcs
# control
#
# Installation:
#
# Before you run this script the first time, you should run the
# following commands
#
# prompt# mkdir /etc/RCS
# prompt# echo "/etc/shadow" | ci -u -i /etc/shadow
#
# This will create the RCS directory and do an initial checkin
# of the shadow file.
#
# Then, to make sure everyone uses this script instead of the
# actual passwd command,
#
# prompt# chmod 700 /usr/bin/passwd
#
# Install this perl program as '/usr/bin/rcspasswd', etc, and tell
# your users to use it instead of passwd (which won't work anymore...)
# You will then need to give it the setuserid bit s.t. it can write
# to /etc/RCS.
#
# prompt# chmod u+s /usr/bin/rcspasswd
#
# If you get errors about the Rcs module not being installed, snag
# it from CPAN, ala
#
# prompt# perl -MCPAN -e 'install Rcs'
#
# Alternate installation:
# (Use carefully, this could break the way your distribution
# handles /etc/shadow.)
# chgrp shadow /usr/bin/rcspasswd /etc/RCS /etc/shadow
# chmod 750 /usr/bin/rcspasswd
# chmod g+s /usr/bin/rcspasswd
# chmod 770 /etc/RCS
# chmod 440 /etc/shadow
#
# (Note that you could make it merely setgid if you play with the
# permissions of /etc/RCS and make a new group instead, your call.)
#
#
#
# Bugs: The user can 'killall -9 rcspasswd' to kill this
# script,leaving the file checked out, affecting a
# DoS on passwd changes.
#
# Notes: Failed password changes are logged via Rcs as such.
# However, a failed password change should result in
# no changes to /etc/shadow, so no Rcs revision would
# be created, and thus this log is effectively discarded.
# But since we're still calling the actual passwd program,
# all it's logging (and PAM if enabled) is still in effect
# anyway, so it's no loss.
$PASSWD_CMD='/usr/bin/passwd'; # Hard code appropriately.
$SHADOW='/etc/shadow'; # Folks aren't using passwd still,
# are they? Please, god, I hope not.
# Ok, no more changes necessary from here down.
sub bail { print STDERR @_, "\n"; checkin(); exit 1; }
require 5.003; # Doesn't have the old suidperl bug.
use Rcs;
use File::Basename;
undef %ENV; # Don't allow user-supplied env,
# avoid current and future bugs with
# environment issues.
$ENV{PATH}="/"; # Prevent any PATH issues.
$ENV{LOGNAME}='root'; # for log entry, again, ignore user
# supplied input.
# Let's not bother with workdir and rcsdir methods for the
# Rcs module, and just cd in and use non fully qualified
# path names.
chdir dirname $SHADOW or bail "Can't cd to ", dirname $SHADOW, "\n";
$SHADOW=basename $SHADOW;
Rcs->quiet(1); # Let's not see random output
Rcs->bindir('/usr/bin'); # Set this to the location where
# you can find 'co', 'ci' and friends.
$shadow = Rcs->new;
$shadow->file($SHADOW);
$SETUID=1 if $> != $<; # Are we running setuid?
$realuid=$<;
$realuname = getpwuid($realuid);
$msg = "rcspasswd change by $realuname.";
# Check out the shadow file. This will also prevent this script
# from running more than once simultaneously, which is a bit of
# duplication given that passwd takes care of shadow locking anyway.
$<=$> if $SETUID; # Needed for Rcs -- it checks real uid,
# annoyingly
$shadow->co('-l'); # This will automatically die's if failure,
# no need for error checking.
# Reset to invoking user for passwd command, and die if we fail,
# otherwise normal users will be running passwd as root.
$SETUID and $< = $realuid and $< != $realuid and bail "Can't reset uid";
# Run the passwd command now, using the arguments supplied.
#
# We don't modify @ARGV at all because we assume that, passwd
# being given the exact same uid/euid it would normally receive
# were this script not in the way, that it will act normal and
# handle all the permissions for us, not allowing 'joe' to
# change the pw for 'bob' etc.
system $PASSWD_CMD, @ARGV;
$msg .= " (ERROR: '$PASSWD_CMD @ARGV' command failed)" if $?;
checkin();
exit 0;
sub checkin {
$<=$>; # Need for Rcs, again.
$shadow->ci('-u',"-m$msg"); # -u to make sure it's checked out again
# s.t. it's avalable for authentication
# like normal. It would suck for /etc/shadow
# to be in RCS only, not in /etc ...
}
|