Diff for /loncom/lcpasswd between versions 1.11 and 1.12

version 1.11, 2000/10/30 03:30:26 version 1.12, 2001/10/23 03:42:30
Line 6 Line 6
 # SH: October 27, 2000  # SH: October 27, 2000
 # SH: October 28, 2000  # SH: October 28, 2000
 # SH: October 29, 2000  # SH: October 29, 2000
   # YEAR=2001
   # Scott Harrison 10/22
   
   ###############################################################################
   ##                                                                           ##
   ## ORGANIZATION OF THIS PERL SCRIPT                                          ##
   ##                                                                           ##
   ## 1. Description of script                                                  ##
   ## 2. Invoking script (standard input only)                                  ##
   ## 3. Example usage inside another piece of code                             ##
   ## 4. Description of functions                                               ##
   ## 5. Exit codes                                                             ##
   ##                                                                           ##
   ###############################################################################
   
 use strict;  use strict;
   
   # ------------------------------------------------------- Description of script
   #
 # This script is a setuid script that should  # This script is a setuid script that should
 # be run by user 'www'.  This script allows  # be run by user 'www'.  This script allows
 # for synchronous entry of passwords into  # for synchronous entry of passwords into
 # both the /etc/passwd and the /etc/smbpasswd  # both the /etc/passwd and the /etc/smbpasswd
 # files.  # files.
   #
 # This script works under the same process control mechanism  # This script works under the same process control mechanism
 # as lcuseradd and lcpasswd, to make sure that only one of these  # as lcuseradd and lcpasswd, to make sure that only one of these
 # processes is running at any one time on the system.  # processes is running at any one time on the system.
   
   # --------------------------------------- Invoking script (standard input only)
   #
 # Standard input usage  # Standard input usage
 # First line is USERNAME  # First line is USERNAME
 # Second line is CURRENT PASSWORD  # Second line is CURRENT PASSWORD
 # Third line is NEW PASSWORD  # Third line is NEW PASSWORD
   #
 # Valid passwords must consist of the  # Valid passwords must consist of the
 # ascii characters within the inclusive  # ascii characters within the inclusive
 # range of 0x20 (32) to 0x7E (126).  # range of 0x20 (32) to 0x7E (126).
Line 31  use strict; Line 49  use strict;
 # SPACE and  # SPACE and
 # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO  # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO
 # PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  # PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
   #
 # Valid user names must consist of ascii  # Valid user names must consist of ascii
 # characters that are alphabetical characters  # characters that are alphabetical characters
 # (A-Z,a-z), numeric (0-9), or the underscore  # (A-Z,a-z), numeric (0-9), or the underscore
 # mark (_). (Essentially, the perl regex \w).  # mark (_). (Essentially, the perl regex \w).
   # User names must begin with an alphabetical character
   # (A-Z,a-z).
   
 # Command-line arguments  # ---------------------------------------------------- Description of functions
 # Yes, but be very careful here (don't pass shell commands)  # enable_root_capability() : have setuid script run as root
 # and this is only supported to allow perl-system calls.  # disable_root_capability() : have setuid script run as www
   # try_to_lock() : make sure that another lcpasswd process isn't running
 # Usage within code  
 # Note: NEVER run as system("/home/httpd/perl/lcpasswd NAME OLDPWD NEWPWD")  
 #  
 # $exitcode=system("/home/httpd/perl/lcpasswd","NAME","OLDPWD","NEWPWD")/256;  
 # print "uh-oh" if $exitcode;  
   
   # ------------------------------------------------------------------ Exit codes
 # These are the exit codes.  # These are the exit codes.
 # ( (0,"ok"),  # ( (0,"ok"),
 #   (1,"User ID mismatch.  This program must be run as user 'www'"),  #   (1,"User ID mismatch.  This program must be run as user 'www'"),
 #   (2,"Error. This program needs 3 command-line arguments (username, old password, new password)."),  #   (2,"Error. This program needs 3 command-line arguments (username, old ".
   #       password, new password)."),
 #   (3,"Error. Three lines need to be entered into standard input."),  #   (3,"Error. Three lines need to be entered into standard input."),
 #   (4,"Error. Too many other simultaneous password change requests being made."),  #   (4,"Error. Too many other simultaneous password change requests being ".
   #       made."),
 #   (5,"Error. User $username does not exist."),  #   (5,"Error. User $username does not exist."),
 #   (6,"Error. Invalid entry of current password."),  #   (6,"Error. Invalid entry of current password."),
 #   (7,"Error. Root was not successfully enabled."),  #   (7,"Error. Root was not successfully enabled."),
 #   (8,"Error. Cannot open /etc/passwd."),  #   (8,"Error. Cannot set password."),
 #   (9,"Error. The user name specified has invalid characters."),  #   (9,"Error. The user name specified has invalid characters."),
 #   (10,"Error. A password entry had an invalid character.") )  #   (10,"Error. A password entry had an invalid character.") )
   
   # ------------------------------------------------------------- Initializations
 # Security  # Security
 $ENV{'PATH'}='/bin:/usr/bin'; # Nullify path information except for what smbpasswd needs  $ENV{'PATH'}='/bin:/usr/bin:/usr/local/sbin:/home/httpd/perl'; # Nullify path
                                                                  # information
 $ENV{'BASH_ENV'}=''; # Nullify shell environment information.  $ENV{'BASH_ENV'}=''; # Nullify shell environment information.
   
 # Do not print error messages if there are command-line arguments  # Do not print error messages
 my $noprint=0;  my $noprint=1;
 if (@ARGV) {  
     $noprint=1;  # ----------------------------- Make sure this process is running from user=www
 }  my $wwwid=getpwnam('www');
   &disable_root_capability;
 # Read in /etc/passwd, and make sure this process is running from user=www  if ($wwwid!=$>) {
 open (IN, '</etc/passwd');      print("User ID mismatch.  This program must be run as user 'www'\n")
 my @lines=<IN>;   unless $noprint;
 close IN;  
 my $wwwid;  
 for my $l (@lines) {  
     chop $l;  
     my @F=split(/\:/,$l);  
     if ($F[0] eq 'www') {$wwwid=$F[2];}  
 }  
 if ($wwwid!=$<) {  
     print("User ID mismatch.  This program must be run as user 'www'\n") unless $noprint;  
     exit 1;      exit 1;
 }  }
   
   # ----------------------------------- Start running script with www permissions
 &disable_root_capability;  &disable_root_capability;
   
 # Handle case of another lcpasswd process  # --------------------------- Handle case of another lcpasswd process (locking)
 unless (&try_to_lock('/tmp/lock_lcpasswd')) {  unless (&try_to_lock('/tmp/lock_lcpasswd')) {
     print "Error. Too many other simultaneous password change requests being made.\n" unless $noprint;      print "Error. Too many other simultaneous password change requests being ".
    "made.\n" unless $noprint;
     exit 4;      exit 4;
 }  }
   
 # Gather input.  Should only be 3 values.  # ------- Error-check input, need 3 values (user name, password 1, password 2).
 my @input;  my @input;
 if (@ARGV==3) {  @input=<>;
     @input=@ARGV;  if (@input!=3) {
 }      print("Error. Three lines need to be entered into standard input.\n")
 elsif (@ARGV) {   unless $noprint;
     print("Error. This program needs 3 command-line arguments (username, old password, new password).\n") unless $noprint;  
     unlink('/tmp/lock_lcpasswd');      unlink('/tmp/lock_lcpasswd');
     exit 2;      exit 3;
 }  
 else {  
     @input=<>;  
     if (@input!=3) {  
  print("Error. Three lines need to be entered into standard input.\n") unless $noprint;  
  unlink('/tmp/lock_lcpasswd');  
  exit 3;  
     }  
     map {chop} @input;  
 }  }
   map {chomp} @input;
   
 my ($username,$oldpwd,$newpwd)=@input;  my ($username,$password1,$password2)=@input;
 $username=~/^(\w+)$/;  $username=~/^(\w+)$/;
 my $safeusername=$1;  my $safeusername=$1;
 if ($username ne $safeusername) {  if (($username ne $safeusername) or ($safeusername!~/^[A-Za-z]/)) {
     print "Error. The user name specified has invalid characters.\n";      print "Error. The user name specified has invalid characters.\n";
     unlink('/tmp/lock_lcpasswd');      unlink('/tmp/lock_lcpasswd');
     exit 9;      exit 9;
 }  }
 my $pbad=0;  my $pbad=0;
 map {if (($_<32)&&($_>126)){$pbad=1;}} (split(//,$oldpwd));  map {if (($_<32)&&($_>126)){$pbad=1;}} (split(//,$password1));
 map {if (($_<32)&&($_>126)){$pbad=1;}} (split(//,$newpwd));  map {if (($_<32)&&($_>126)){$pbad=1;}} (split(//,$password2));
 if ($pbad) {  if ($pbad) {
     print "Error. A password entry had an invalid character.\n";      print "Error. A password entry had an invalid character.\n";
     unlink('/tmp/lock_lcpasswd');      unlink('/tmp/lock_lcpasswd');
     exit 10;      exit 10;
 }  }
   
 # Grab the line corresponding to username  # -- Only add user if the two password arguments match.
 my ($userid,$useroldcryptpwd);  if ($password1 ne $password2) {
 my @F; my @U;      print "Error. Password mismatch.\n" unless $noprint;
 for my $l (@lines) {      unlink('/tmp/lock_lcpasswd');
     @F=split(/\:/,$l);      exit 13;
     if ($F[0] eq $username) {($userid,$useroldcryptpwd)=($F[2],$F[1]); @U=@F;}  
 }  }
   
 # Verify existence of user  # Verify existence of user
 if (!defined($userid)) {  unless(getpwnam($safeusername)) {
     print "Error. User $username does not exist.\n" unless $noprint;      print "Error. User $username does not exist.\n" unless $noprint;
     unlink('/tmp/lock_lcpasswd');      unlink('/tmp/lock_lcpasswd');
     exit 5;      exit 5;
 }  }
   
 # Verify password entry  &enable_root_capability;
 if (crypt($oldpwd,$useroldcryptpwd) ne $useroldcryptpwd) {  ($>,$<)=(0,0);
     print "Error. Invalid entry of current password.\n" unless $noprint;  open OUT,"|pwchange $safeusername";
     unlink('/tmp/lock_lcpasswd');  print OUT $password1;
     exit 6;  print OUT "\n";
 }  close OUT;
   ($>,$<)=(0,500);
   
 # Construct new password entry (random salt)  if ($?) {
 my $newcryptpwd=crypt($newpwd,(join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]));      exit 8;
 $U[1]=$newcryptpwd;  
 my $userline=join(':',@U);  
 my $rootid=&enable_root_capability;  
 if ($rootid!=0) {  
     print "Error.  Root was not successfully enabled.\n" unless $noprint;  
     unlink('/tmp/lock_lcpasswd');  
     exit 7;  
 }  }
 open PASSWORDFILE, '>/etc/passwd' or (print("Error.  Cannot open /etc/passwd.\n") && unlink('/tmp/lock_lcpasswd') && exit(8));  my $userid=getpwnam($safeusername);
 for my $l (@lines) {  
     @F=split(/\:/,$l);  unless (-e '/usr/bin/smbpasswd') {
     if ($F[0] eq $username) {print PASSWORDFILE "$userline\n";}  
     else {print PASSWORDFILE "$l\n";}      ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid
 }                     # environment
 close PASSWORDFILE;      unless (-e '/etc/smbpasswd') {
    open (OUT,'>/etc/smbpasswd'); close OUT;
 ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid environment      }
 unless (-e '/etc/smbpasswd') {  
     open (OUT,'>/etc/smbpasswd'); close OUT;      my $smbexist=0;
 }      open (IN, '</etc/smbpasswd');
 my $smbexist=0;      my @lines=<IN>;
 open (IN, '</etc/smbpasswd');      close IN;
 my @lines=<IN>;      for my $l (@lines) {
 close IN;   chop $l;
 for my $l (@lines) {   my @F=split(/\:/,$l);
     chop $l;   if ($F[0] eq $username) {$smbexist=1;}
     my @F=split(/\:/,$l);      }
     if ($F[0] eq $username) {$smbexist=1;}      unless ($smbexist) {
 }   open(OUT,'>>/etc/smbpasswd');
 unless ($smbexist) {   print OUT join(':',($safeusername,$userid,
     open(OUT,'>>/etc/smbpasswd');      'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXX'.
     print OUT join(':',($safeusername,$userid,'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX','','/home/'.$safeusername,'/bin/bash')) . "\n";      'XXXXXXXXXXXXXXXXXX','','/home/'.$safeusername,
       '/bin/bash')) . "\n";
    close OUT;
       }
   
       open(OUT,"|/usr/bin/smbpasswd -s $safeusername>/dev/null");
       print OUT $password2; print OUT "\n";
       print OUT $password2; print OUT "\n";
     close OUT;      close OUT;
       $<=$wwwid; # unfool the program
 }  }
 open(OUT,"|/usr/bin/smbpasswd -s $safeusername>/dev/null");  
 print OUT $newpwd; print OUT "\n";  
 print OUT $newpwd; print OUT "\n";  
 close OUT;  
 $<=$wwwid; # unfool the program  
 &disable_root_capability;  &disable_root_capability;
 unlink('/tmp/lock_lcpasswd');  unlink('/tmp/lock_lcpasswd');
 exit 0;  exit 0;
   
 # ----------------------------------------------------------- have setuid script run as root  # ---------------------------------------------- have setuid script run as root
 sub enable_root_capability {  sub enable_root_capability {
     if ($wwwid==$>) {      if ($wwwid==$>) {
  ($<,$>)=($>,$<);   ($<,$>)=($>,$<);
Line 208  sub enable_root_capability { Line 210  sub enable_root_capability {
     return $>;      return $>;
 }  }
   
 # ----------------------------------------------------------- have setuid script run as www  # ----------------------------------------------- have setuid script run as www
 sub disable_root_capability {  sub disable_root_capability {
     if ($wwwid==$<) {      if ($wwwid==$<) {
  ($<,$>)=($>,$<);   ($<,$>)=($>,$<);
Line 219  sub disable_root_capability { Line 221  sub disable_root_capability {
     }      }
 }  }
   
 # ----------------------------------- make sure that another lcpasswd process isn't running  # ----------------------- make sure that another lcpasswd process isn't running
 sub try_to_lock {  sub try_to_lock {
     my ($lockfile)=@_;      my ($lockfile)=@_;
     my $currentpid;      my $currentpid;

Removed from v.1.11  
changed lines
  Added in v.1.12


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