Perl script - changing passwords

Just wanted options of this - first 'real' Perl script and I'm not positive of all the quirks in Perl. Any suggestions are welcome.
Especially since I'm messing with /etc/shadow! Running Solaris 2.6, Perl 5.005.03

#!/u/bin/perl
# 
#  Change the user's old password to the new in /etc/shadow 
#  Expects userID, old password, new password
#  Will only change ftp users passwords - 
#       HOG 04/25/02 It's Alive!
# ====================================================================
# Set up variables ------------
$user = "$ARGV[0]";
$oldpass = "$ARGV[1]";
$newpass = "$ARGV[2]";
$oldshadow = "/etc/shadow";
$newshadow = "/etc/.newshadow";
#
# ==== Check that there is only one of user =====
$useramount = `/usr/bin/grep -c $user /etc/shadow`;
if ($useramount != 1) { die "More or less than one"; }
#
$userinfo = `/usr/bin/grep $user /etc/shadow`;
($user1, $passwd, $epoch, $passextra) = split(/:/, $userinfo, 4);
$salt = substr($passwd,0,2);
$newsalt = join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
#
# Put testing junk here (print variables)
#
    if (crypt($oldpass, $salt) ne $passwd) {
        # =========== FAILED - write to messages file - return error =========
        system("/usr/bin/echo \" progserver chgpwd: ERROR changing $user passwor
d\" >> /var/adm/messages");
        die "";
    } else {
        $newcrypt = crypt($newpass, $newsalt);
        $nowepoch = (time () /60 /60 /24 ) + 35;
        ($newepoch, $junk) = split(/\./, $nowepoch, 2);
        chomp($userinfo1 = "$user1:$newcrypt:$newepoch:$passextra");
        # Make a backup copy if none exists - done nightly in another script
        if (!-e "/etc/.oldshadow") { `/usr/bin/cp /etc/shadow /etc/.oldshadow` }
        &create_newfile;
        `/usr/bin/cp $newshadow $oldshadow`;
        #
    }
sub create_newfile {
        open NEWSHAD, ">$newshadow" or die "Can not open new shadow\n";
        open OLDSHAD, "<$oldshadow" or die "Can not open old shadow\n";
        while (<OLDSHAD>) {
                ($usertmp, $everythingelse) = split(/:/, $_, 2);
                if ("$usertmp" eq "$user") {
                        print NEWSHAD "$userinfo1\n";
                } else {
                        print NEWSHAD "$_";
                }
        }
                close OLDSHAD;
                close NEWSHAD;
}

Is not necesary to do the job with perl, there are a post to change password with expect.

Script to change UNIX password (In shell programming and scripting).

Regards. Hugo.

I think that you are writing this for SunOS. I don't know SunOS super well, but I think you missed an issue.

With the versions of UNIX that I do know, programs like passwd use some kind of locking scheme. This prevents two or more users from stepping on each other if they to change their password at the same time.

With early versions of Unix, the trick was to invoke the link system call to link /etc/passwd to /etc/ptmp. The link system call is atomic. And it will fail, even for root, if the target exists. If the link was successful, the program could proceed. If not, it would back off. Sysadmins would get a call from a user sometimes about the password file being locked. The trick was then to remove /etc/ptmp. HP-UX was still using this method a few years ago, but I haven't checked since HP-UX 9.0.

Beats me what Sun is using. I just ran the passwd command on a Sun. A "lt -ltc /etc | head" showed that oshadow had popped into existence. It is listed without comment on Sun's man page for passwd.

If you going to run the script in single user mode you can ignore this issue. Otherwise, you might want to do some research....

Hugo,

I don't have expect loaded on any system but since Perl was there...thanks thou.

Perderabo,

/etc/oshadow is a link to /etc/shadow on Solaris. If you do a checksum against both you will see it.
The password lock is done with /etc/.pwd.lock - thanks for the tip, I'll look into what I need to change.