Annotation of loncom/lcpasswd, revision 1.4

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
1.4     ! harris41   11: # be run by user 'www'.  This script allows
        !            12: # for synchronous entry of passwords into
        !            13: # both the /etc/passwd and the /etc/smbpasswd
        !            14: # files.
1.1       harris41   15: 
                     16: # Standard input usage
                     17: # First line is USERNAME
                     18: # Second line is CURRENT PASSWORD
                     19: # Third line is NEW PASSWORD
                     20: 
1.4     ! harris41   21: # Command-line arguments
        !            22: # Yes, but be very careful here (don't pass shell commands)
        !            23: # and this is only supported to allow perl-system calls.
        !            24: 
        !            25: # Usage within code
        !            26: # Note: NEVER run as system("NAME OLDPWD NEWPWD")
        !            27: #
        !            28: # $exitcode=system("NAME","OLDPWD","NEWPWD")/256;
        !            29: # print "uh-oh" if $exitcode;
        !            30: 
        !            31: # These are the exit codes.
        !            32: # ( (0,"ok"),
        !            33: #   (1,"User ID mismatch.  This program must be run as user 'www'),
        !            34: #   (2,"Error. This program does not accept command-line arguments."),
        !            35: #   (3,"Error. Three lines need to be entered into standard input.\n"),
        !            36: #   (4,"Error. Too many other simultaneous password change requests being made.\n"),
        !            37: #   (5,"Error. User $username does not exist.\n"),
        !            38: #   (6,"Error. Invalid entry of current password.\n"),
        !            39: #   (7,"Error.  Root was not successfully enabled.\n") )
        !            40: 
1.1       harris41   41: # Security
1.2       harris41   42: $ENV{'PATH'}="/bin:/usr/bin"; # Nullify path information except for what smbpasswd needs
1.1       harris41   43: $ENV{'BASH_ENV'}=""; # Nullify shell environment information.
                     44: 
1.4     ! harris41   45: # Do not print error messages if there are command-line arguments
        !            46: my $noprint=0;
        !            47: if (@ARGV) {
        !            48:     $noprint=1;
        !            49: }
        !            50: 
1.1       harris41   51: open (IN, "</etc/passwd");
                     52: my @lines=<IN>;
                     53: close IN;
                     54: my $wwwid;
                     55: for my $l (@lines) {
                     56:     chop $l;
                     57:     my @F=split(/\:/,$l);
                     58:     if ($F[0] eq 'www') {$wwwid=$F[2];}
                     59: }
                     60: if ($wwwid!=$<) {
1.4     ! harris41   61:     print("User ID mismatch.  This program must be run as user 'www'\n") unless $noprint;
        !            62:     exit 1;
1.1       harris41   63: }
1.2       harris41   64: &disable_root_capability;
1.1       harris41   65: 
1.4     ! harris41   66: # Gather input.  Should only be 3 values.
        !            67: my @input;
        !            68: if (@ARGV==3) {
        !            69:     @input=@ARGV;
        !            70: }
        !            71: elsif (@ARGV) {
        !            72:     print("Error. This program needs 3 command-line arguments (username, old password, new password).\n") unless $noprint;
        !            73:     exit 2;
        !            74: }
        !            75: else {
        !            76:     @input=<>;
        !            77:     if (@input!=3) {
        !            78: 	print("Error. Three lines need to be entered into standard input.\n") unless $noprint;
        !            79: 	exit 3;
        !            80:     }
        !            81:     map {chop} @input;
1.1       harris41   82: }
                     83: # Handle case of another lcpasswd process
                     84: unless (&try_to_lock("/tmp/lock_lcpasswd")) {
1.4     ! harris41   85:     print "Error. Too many other simultaneous password change requests being made.\n" unless $noprint;
        !            86:     exit 4;
1.1       harris41   87: }
                     88: 
1.4     ! harris41   89: my ($username,$oldpwd,$newpwd)=@input;
1.1       harris41   90: 
                     91: # Grab the line corresponding to username
                     92: my ($userid,$useroldcryptpwd);
                     93: my @F; my @U;
                     94: for my $l (@lines) {
                     95:     @F=split(/\:/,$l);
                     96:     if ($F[0] eq $username) {($userid,$useroldcryptpwd)=($F[2],$F[1]); @U=@F;}
                     97: }
                     98: 
                     99: # Verify existence of user
                    100: if (!defined($userid)) {
1.4     ! harris41  101:     print "Error. User $username does not exist.\n" unless $noprint;
        !           102:     unlink("/tmp/lock_lcpasswd");
        !           103:     exit 5;
1.1       harris41  104: }
                    105: 
                    106: # Verify password entry
                    107: if (crypt($oldpwd,$useroldcryptpwd) ne $useroldcryptpwd) {
1.4     ! harris41  108:     print "Error. Invalid entry of current password.\n" unless $noprint;
        !           109:     unlink("/tmp/lock_lcpasswd");
        !           110:     exit 6;
1.1       harris41  111: }
                    112: 
1.2       harris41  113: # Construct new password entry (random salt)
                    114: my $newcryptpwd=crypt($newpwd,(join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]));
1.1       harris41  115: $U[1]=$newcryptpwd;
                    116: my $userline=join(":",@U);
1.2       harris41  117: my $rootid=&enable_root_capability;
                    118: if ($rootid!=0) {
1.4     ! harris41  119:     print "Error.  Root was not successfully enabled.\n" unless $noprint;
        !           120:     unlink("/tmp/lock_lcpasswd");
        !           121:     exit 7;
1.2       harris41  122: }
                    123: open PASSWORDFILE, ">/etc/passwd" or die("Cannot open /etc/passwd!");
1.1       harris41  124: for my $l (@lines) {
                    125:     @F=split(/\:/,$l);
                    126:     if ($F[0] eq $username) {print PASSWORDFILE "$userline\n";}
                    127:     else {print PASSWORDFILE "$l\n";}
                    128: }
                    129: close PASSWORDFILE;
1.2       harris41  130: $username=~/^(\w+)$/;
                    131: my $safeusername=$1;
                    132: ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid environment
                    133: unless (-e "/etc/smbpasswd") {
                    134:     open (OUT,">/etc/smbpasswd"); close OUT;
                    135: }
                    136: my $smbexist=0;
                    137: open (IN, "</etc/smbpasswd");
                    138: my @lines=<IN>;
                    139: close IN;
                    140: for my $l (@lines) {
                    141:     chop $l;
                    142:     my @F=split(/\:/,$l);
                    143:     if ($F[0] eq $username) {$smbexist=1;}
                    144: }
                    145: unless ($smbexist) {
                    146:     open(OUT,">>/etc/smbpasswd");
                    147:     print OUT join(":",($safeusername,$userid,'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX','','/home/'.$safeusername,'/bin/bash')) . "\n";
                    148:     close OUT;
                    149: }
                    150: open(OUT,"|/usr/bin/smbpasswd -s $safeusername>/dev/null");
                    151: print OUT $newpwd; print OUT "\n";
                    152: print OUT $newpwd; print OUT "\n";
                    153: close OUT;
                    154: $<=$wwwid; # unfool the program
1.1       harris41  155: &disable_root_capability;
                    156: unlink("/tmp/lock_lcpasswd");
1.4     ! harris41  157: exit 0;
1.1       harris41  158: 
1.4     ! harris41  159: # ----------------------------------------------------------- have setuid script run as root
1.1       harris41  160: sub enable_root_capability {
1.2       harris41  161:     if ($wwwid==$>) {
1.1       harris41  162: 	($<,$>)=($>,$<);
                    163: 	($(,$))=($),$();
                    164:     }
                    165:     else {
                    166: 	# root capability is already enabled
                    167:     }
1.2       harris41  168:     return $>;
1.1       harris41  169: }
                    170: 
1.4     ! harris41  171: # ----------------------------------------------------------- have setuid script run as www
1.1       harris41  172: sub disable_root_capability {
1.2       harris41  173:     if ($wwwid==$<) {
1.1       harris41  174: 	($<,$>)=($>,$<);
                    175: 	($(,$))=($),$();
                    176:     }
                    177:     else {
                    178: 	# root capability is already disabled
                    179:     }
                    180: }
                    181: 
1.4     ! harris41  182: # ----------------------------------- make sure that another lcpasswd process isn't running
1.1       harris41  183: sub try_to_lock {
                    184:     my ($lockfile)=@_;
                    185:     my $currentpid;
                    186:     my $lastpid;
                    187:     for (0..10) {
                    188: 	if (-e $lockfile) {
                    189: 	    open(LOCK,"<$lockfile");
                    190: 	    $currentpid=<LOCK>;
                    191: 	    close LOCK;
                    192: 	    if ($currentpid==$lastpid) {
                    193: 		last;
                    194: 	    }
                    195: 	    sleep 3;
                    196: 	    $lastpid=$currentpid;
                    197: 	}
                    198: 	else {
                    199: 	    last;
                    200: 	}
                    201: 	if ($_==10) {
                    202: 	    return 0;
                    203: 	}
                    204:     }
                    205:     open(LOCK,">$lockfile");
                    206:     print LOCK $$;
                    207:     close LOCK;
                    208:     return 1;
                    209: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.