#!/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 ... }