Annotation of loncom/lcpasswd, revision 1.3

1.1       harris41    1: #!/usr/bin/perl
1.3     ! harris41    2: #
        !             3: # lcpasswd
        !             4: #
        !             5: # Scott Harrison
        !             6: # October 27, 2000
1.1       harris41    7: 
                      8: use strict;
                      9: 
                     10: # This script is a setuid script that should
                     11: # be run by user 'www'.
                     12: 
                     13: # Standard input usage
                     14: # First line is USERNAME
                     15: # Second line is CURRENT PASSWORD
                     16: # Third line is NEW PASSWORD
                     17: 
                     18: # Security
1.2       harris41   19: $ENV{'PATH'}="/bin:/usr/bin"; # Nullify path information except for what smbpasswd needs
1.1       harris41   20: $ENV{'BASH_ENV'}=""; # Nullify shell environment information.
                     21: 
                     22: open (IN, "</etc/passwd");
                     23: my @lines=<IN>;
                     24: close IN;
                     25: my $wwwid;
                     26: for my $l (@lines) {
                     27:     chop $l;
                     28:     my @F=split(/\:/,$l);
                     29:     if ($F[0] eq 'www') {$wwwid=$F[2];}
                     30: }
                     31: if ($wwwid!=$<) {
                     32:     print("User ID mismatch.  This program must be run as user 'www'\n");
                     33:     exit 0;
                     34: }
1.2       harris41   35: &disable_root_capability;
1.1       harris41   36: if (@ARGV) {
                     37:     print("Error. This program does not accept command-line arguments.\n");
                     38:     exit 0;
                     39: }
                     40: 
                     41: # Gather input from standard input.  Should only be 3 lines.
                     42: my @input=<>;
                     43: if (@input!=3) {
                     44:     print("Error. Three lines need to be entered into standard input.\n");
                     45:     exit 0;
                     46: }
                     47: 
                     48: # Handle case of another lcpasswd process
                     49: unless (&try_to_lock("/tmp/lock_lcpasswd")) {
                     50:     print "Error. Too many other simultaneous password change requests being made.\n";
                     51:     exit 0;
                     52: }
                     53: 
                     54: my ($username,$oldpwd,$newpwd)=map {chop; $_} @input;
                     55: 
                     56: # Grab the line corresponding to username
                     57: my ($userid,$useroldcryptpwd);
                     58: my @F; my @U;
                     59: for my $l (@lines) {
                     60:     @F=split(/\:/,$l);
                     61:     if ($F[0] eq $username) {($userid,$useroldcryptpwd)=($F[2],$F[1]); @U=@F;}
                     62: }
                     63: 
                     64: # Verify existence of user
                     65: if (!defined($userid)) {
                     66:     print "Error. User $username does not exist.\n";
                     67:     exit 0;
                     68: }
                     69: 
                     70: # Verify password entry
                     71: if (crypt($oldpwd,$useroldcryptpwd) ne $useroldcryptpwd) {
                     72:     print "Error. Invalid entry of current password.\n";
                     73:     exit 0;
                     74: }
                     75: 
1.2       harris41   76: # Construct new password entry (random salt)
                     77: my $newcryptpwd=crypt($newpwd,(join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]));
1.1       harris41   78: $U[1]=$newcryptpwd;
                     79: my $userline=join(":",@U);
1.2       harris41   80: my $rootid=&enable_root_capability;
                     81: if ($rootid!=0) {
                     82:     print "Error.  Root was not successfully enabled.\n";
                     83:     exit 0;
                     84: }
                     85: open PASSWORDFILE, ">/etc/passwd" or die("Cannot open /etc/passwd!");
1.1       harris41   86: for my $l (@lines) {
                     87:     @F=split(/\:/,$l);
                     88:     if ($F[0] eq $username) {print PASSWORDFILE "$userline\n";}
                     89:     else {print PASSWORDFILE "$l\n";}
                     90: }
                     91: close PASSWORDFILE;
1.2       harris41   92: $username=~/^(\w+)$/;
                     93: my $safeusername=$1;
                     94: ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid environment
                     95: unless (-e "/etc/smbpasswd") {
                     96:     open (OUT,">/etc/smbpasswd"); close OUT;
                     97: }
                     98: my $smbexist=0;
                     99: open (IN, "</etc/smbpasswd");
                    100: my @lines=<IN>;
                    101: close IN;
                    102: for my $l (@lines) {
                    103:     chop $l;
                    104:     my @F=split(/\:/,$l);
                    105:     if ($F[0] eq $username) {$smbexist=1;}
                    106: }
                    107: unless ($smbexist) {
                    108:     open(OUT,">>/etc/smbpasswd");
                    109:     print OUT join(":",($safeusername,$userid,'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX','','/home/'.$safeusername,'/bin/bash')) . "\n";
                    110:     close OUT;
                    111: }
                    112: open(OUT,"|/usr/bin/smbpasswd -s $safeusername>/dev/null");
                    113: print OUT $newpwd; print OUT "\n";
                    114: print OUT $newpwd; print OUT "\n";
                    115: close OUT;
                    116: $<=$wwwid; # unfool the program
1.1       harris41  117: &disable_root_capability;
                    118: unlink("/tmp/lock_lcpasswd");
                    119: 
                    120: sub enable_root_capability {
1.2       harris41  121:     if ($wwwid==$>) {
1.1       harris41  122: 	($<,$>)=($>,$<);
                    123: 	($(,$))=($),$();
                    124:     }
                    125:     else {
                    126: 	# root capability is already enabled
                    127:     }
1.2       harris41  128:     return $>;
1.1       harris41  129: }
                    130: 
                    131: sub disable_root_capability {
1.2       harris41  132:     if ($wwwid==$<) {
1.1       harris41  133: 	($<,$>)=($>,$<);
                    134: 	($(,$))=($),$();
                    135:     }
                    136:     else {
                    137: 	# root capability is already disabled
                    138:     }
                    139: }
                    140: 
                    141: sub try_to_lock {
                    142:     my ($lockfile)=@_;
                    143:     my $currentpid;
                    144:     my $lastpid;
                    145:     for (0..10) {
                    146: 	if (-e $lockfile) {
                    147: 	    open(LOCK,"<$lockfile");
                    148: 	    $currentpid=<LOCK>;
                    149: 	    close LOCK;
                    150: 	    if ($currentpid==$lastpid) {
                    151: 		last;
                    152: 	    }
                    153: 	    sleep 3;
                    154: 	    $lastpid=$currentpid;
                    155: 	}
                    156: 	else {
                    157: 	    last;
                    158: 	}
                    159: 	if ($_==10) {
                    160: 	    return 0;
                    161: 	}
                    162:     }
                    163:     open(LOCK,">$lockfile");
                    164:     print LOCK $$;
                    165:     close LOCK;
                    166:     return 1;
                    167: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>