Diff for /loncom/lcpasswd between versions 1.4 and 1.22

version 1.4, 2000/10/27 23:32:24 version 1.22, 2010/10/12 10:33:47
Line 1 Line 1
 #!/usr/bin/perl  #!/usr/bin/perl
   # The Learning Online Network with CAPA
 #  #
 # lcpasswd  # lcpasswd - LON-CAPA setuid script to synchronously change all
   #            filesystem-related passwords (samba, unix, etc)
 #  #
 # Scott Harrison  # YEAR=2002
 # October 27, 2000  # 02/19 Matthew Hall
   #
   # $Id$
   ###
   
   ###############################################################################
   ##                                                                           ##
   ## 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
   # as lcuseradd and lcpasswd, to make sure that only one of these
   # 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 NEW PASSWORD
 # Third line is NEW PASSWORD  # Third line is NEW PASSWORD
   
 # Command-line arguments  
 # Yes, but be very careful here (don't pass shell commands)  
 # and this is only supported to allow perl-system calls.  
   
 # Usage within code  
 # Note: NEVER run as system("NAME OLDPWD NEWPWD")  
 #  #
 # $exitcode=system("NAME","OLDPWD","NEWPWD")/256;  # Valid passwords must consist of the
 # print "uh-oh" if $exitcode;  # ascii characters within the inclusive
   # range of 0x20 (32) to 0x7E (126).
   # These characters are:
   # SPACE and
   # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO
   # PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
   #
   # Valid user names must consist of ascii
   # characters that are alphabetical characters
   # (A-Z,a-z), numeric (0-9), or the underscore
   # mark (_). (Essentially, the perl regex \w).
   # User names must begin with an alphabetical character
   # (A-Z,a-z).
   
   # ---------------------------------------------------- Description of functions
   # enable_root_capability() : have setuid script run as root
   # disable_root_capability() : have setuid script run as www
   # try_to_lock() : make sure that another lcpasswd process isn't running
   
   # ------------------------------------------------------------------ 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 does not accept command-line arguments."),  #   (2,"Error. This program needs 3 command-line arguments (username, old ".
 #   (3,"Error. Three lines need to be entered into standard input.\n"),  #       password, new password)."),
 #   (4,"Error. Too many other simultaneous password change requests being made.\n"),  #   (3,"Error. Three lines need to be entered into standard input."),
 #   (5,"Error. User $username does not exist.\n"),  #   (4,"Error. Too many other simultaneous password change requests being ".
 #   (6,"Error. Invalid entry of current password.\n"),  #       made."),
 #   (7,"Error.  Root was not successfully enabled.\n") )  #   (5,"Error. User $username does not exist."),
   #   (6,"Error. Invalid entry of current password."),
   #   (7,"Error. Root was not successfully enabled."),
   #   (8,"Error. Cannot set password."),
   #   (9,"Error. The user name specified has invalid characters."),
   #   (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
 $ENV{'BASH_ENV'}=""; # Nullify shell environment information.                                                                 # information
   delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # nullify potential taints
   
   # Do not print error messages
   my $noprint=1;
   
   print "In lcpasswd" unless $noprint;
   
   # ----------------------------- Make sure this process is running from user=www
   my $wwwid=getpwnam('www');
   
 # Do not print error messages if there are command-line arguments  
 my $noprint=0;  
 if (@ARGV) {  
     $noprint=1;  
 }  
   
 open (IN, "</etc/passwd");  
 my @lines=<IN>;  
 close IN;  
 my $wwwid;  
 for my $l (@lines) {  
     chop $l;  
     my @F=split(/\:/,$l);  
     if ($F[0] eq 'www') {$wwwid=$F[2];}  
 }  
 if ($wwwid!=$<) {  if ($wwwid!=$<) {
     print("User ID mismatch.  This program must be run as user 'www'\n") unless $noprint;      print("User ID mismatch.  This program must be run as user 'www'\n")
    unless $noprint;
     exit 1;      exit 1;
 }  }
 &disable_root_capability;  
   
 # Gather input.  Should only be 3 values.  # ----------------------------------- Start running script with www permissions
 my @input;  
 if (@ARGV==3) {  
     @input=@ARGV;  # --------------------------- Handle case of another lcpasswd process (locking)
 }  unless (&try_to_lock('/tmp/lock_lcpasswd')) {
 elsif (@ARGV) {      print "Error. Too many other simultaneous password change requests being ".
     print("Error. This program needs 3 command-line arguments (username, old password, new password).\n") unless $noprint;   "made.\n" unless $noprint;
     exit 2;  
 }  
 else {  
     @input=<>;  
     if (@input!=3) {  
  print("Error. Three lines need to be entered into standard input.\n") unless $noprint;  
  exit 3;  
     }  
     map {chop} @input;  
 }  
 # Handle case of another lcpasswd process  
 unless (&try_to_lock("/tmp/lock_lcpasswd")) {  
     print "Error. Too many other simultaneous password change requests being made.\n" unless $noprint;  
     exit 4;      exit 4;
 }  }
   
 my ($username,$oldpwd,$newpwd)=@input;  # ------- Error-check input, need 3 values (user name, password 1, password 2).
   my @input;
   @input=<>;
   if (@input!=3) {
       print("Error. Three lines need to be entered into standard input.\n")
    unless $noprint;
       unlink('/tmp/lock_lcpasswd');
       exit 3;
   }
   foreach (@input) {chomp;}
   
 # Grab the line corresponding to username  my ($username,$password1,$password2)=@input;
 my ($userid,$useroldcryptpwd);  $username=~/^(\w+)$/;
 my @F; my @U;  my $safeusername=$1;
 for my $l (@lines) {  if (($username ne $safeusername) or ($safeusername!~/^[A-Za-z]/)) {
     @F=split(/\:/,$l);      print "Error. The user name specified has invalid characters.\n";
     if ($F[0] eq $username) {($userid,$useroldcryptpwd)=($F[2],$F[1]); @U=@F;}      unlink('/tmp/lock_lcpasswd');
       exit 9;
   }
   my $pbad=0;
   foreach (split(//,$password1)) {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}}
   foreach (split(//,$password2)) {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}}
   if ($pbad) {
       print "Error. A password entry had an invalid character.\n";
       unlink('/tmp/lock_lcpasswd');
       exit 10;
   }
   
   # -- Only add user if the two password arguments match.
   if ($password1 ne $password2) {
       print "Error. Password mismatch.\n" unless $noprint;
       unlink('/tmp/lock_lcpasswd');
       exit 13;
 }  }
   
 # 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;
 }  }
   &enable_root_capability;
   ($>,$<)=(0,0);
   
   print "Now $> , $< , -invoking pwchange with $safeusername $password1"
       unless $noprint;
   open OUT,"|pwchange $safeusername";
   print OUT $password1;
   print OUT "\n";
   close OUT;
   ($>,$<)=(0,$wwwid);
   
   print "pwchange done, back to uid $wwwid" unless $noprint;
   
 # Verify password entry  if ($?) {
 if (crypt($oldpwd,$useroldcryptpwd) ne $useroldcryptpwd) {      exit 8;
     print "Error. Invalid entry of current password.\n" unless $noprint;  
     unlink("/tmp/lock_lcpasswd");  
     exit 6;  
 }  
   
 # Construct new password entry (random salt)  
 my $newcryptpwd=crypt($newpwd,(join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]));  
 $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 die("Cannot open /etc/passwd!");  
 for my $l (@lines) {  
     @F=split(/\:/,$l);  
     if ($F[0] eq $username) {print PASSWORDFILE "$userline\n";}  
     else {print PASSWORDFILE "$l\n";}  
 }  }
 close PASSWORDFILE;  my $userid=getpwnam($safeusername);
 $username=~/^(\w+)$/;  
 my $safeusername=$1;  if (-e '/usr/bin/smbpasswd') {
 ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid environment  
 unless (-e "/etc/smbpasswd") {      ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid
     open (OUT,">/etc/smbpasswd"); close OUT;                     # environment
 }  
 my $smbexist=0;  #   If the -a switch is put on the smbpasswd
 open (IN, "</etc/smbpasswd");  # command line, either a new entry will be created or the old one
 my @lines=<IN>;  # will be used. 
 close IN;  # Therefore the old strategy of looking for and adding a dummy entry is 
 for my $l (@lines) {  # not needed... Finally, the smbpasswd file is in /etc/samba not 
     chop $l;  # /etc/smbpasswd as older versions of the script implied.
     my @F=split(/\:/,$l);  
     if ($F[0] eq $username) {$smbexist=1;}      print "Running smbpasswd" unless $noprint;
 }      open(OUT,"|/usr/bin/smbpasswd -s -a $safeusername>/dev/null") or
 unless ($smbexist) {   die('cannot run smbpasswd');
     open(OUT,">>/etc/smbpasswd");      print OUT $password2; print OUT "\n";
     print OUT join(":",($safeusername,$userid,'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX','','/home/'.$safeusername,'/bin/bash')) . "\n";      print OUT $password2; print OUT "\n";
     close OUT;      close OUT;
       $<=$wwwid; # unfool the program
       print "smbpasswd done" unless $noprint;
 }  }
 open(OUT,"|/usr/bin/smbpasswd -s $safeusername>/dev/null");  
 print OUT $newpwd; print OUT "\n";  
 print OUT $newpwd; print OUT "\n";  unlink('/tmp/lock_lcpasswd');
 close OUT;  
 $<=$wwwid; # unfool the program  
 &disable_root_capability;  
 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==$>) {
  ($<,$>)=($>,$<);   ($<,$>)=($>,0);
  ($(,$))=($),$();   ($(,$))=($),0);
     }      }
     else {      else {
  # root capability is already enabled   # root capability is already enabled
Line 168  sub enable_root_capability { Line 206  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 179  sub disable_root_capability { Line 217  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;
     my $lastpid;      my $lastpid;
   
       # Try to generate lock file.
       # Wait 3 seconds.  If same process id is in
       # lock file, then assume lock file is stale, and
       # go ahead.  If process id's fluctuate, try
       # for a maximum of 10 times.
     for (0..10) {      for (0..10) {
  if (-e $lockfile) {   if (-e $lockfile) {
     open(LOCK,"<$lockfile");      open(LOCK,"<$lockfile");
Line 207  sub try_to_lock { Line 251  sub try_to_lock {
     close LOCK;      close LOCK;
     return 1;      return 1;
 }  }
   
   =head1 NAME
   
   lcpasswd - LON-CAPA setuid script to synchronously change all
              filesystem-related passwords (samba, unix, etc)
   
   =head1 DESCRIPTION
   
   LON-CAPA setuid script to synchronously change all
   filesystem-related passwords (samba, unix, etc)
   
   =head1 README
   
   LON-CAPA setuid script to synchronously change all
   filesystem-related passwords (samba, unix, etc)
   
   =head1 PREREQUISITES
   
   =head1 COREQUISITES
   
   =pod OSNAMES
   
   linux
   
   =pod SCRIPT CATEGORIES
   
   LONCAPA/Administrative
   
   =cut

Removed from v.1.4  
changed lines
  Added in v.1.22


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.