Annotation of loncom/lcpasswd, revision 1.2

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

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