Diff for /loncom/lcpasswd between versions 1.1 and 1.17

version 1.1, 2000/10/27 19:50:24 version 1.17, 2002/09/16 13:27:40
Line 1 Line 1
 #!/usr/bin/perl  #!/usr/bin/perl
   
 use strict;  # The Learning Online Network with CAPA
   #
   # lcpasswd - LON-CAPA setuid script to synchronously change all
   #            filesystem-related passwords (samba, unix, etc)
   #
   # YEAR=2000
   # 10/27,10/28,10/29,10/30 Scott Harrison
   #
   # YEAR=2001
   # 10/22,10/23,11/13,11/15 Scott Harrison
   # 
   # YEAR=2002
   # 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                                                             ##
   ##                                                                           ##
   ###############################################################################
   
 # Scott Harrison  use strict;
 # October 27, 2000  
   
   # ------------------------------------------------------- Description of script
   #
 # This script is a setuid script that should  # This script is a setuid script that should
 # be run by user 'www'.  # be run by user 'www'.  This script allows
   # for synchronous entry of passwords into
   # both the /etc/passwd and the /etc/smbpasswd
   # 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
   #
   # Valid passwords must consist of the
   # 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.
   # ( (0,"ok"),
   #   (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)."),
   #   (3,"Error. Three lines need to be entered into standard input."),
   #   (4,"Error. Too many other simultaneous password change requests being ".
   #       made."),
   #   (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'}=""; # Nullify path information.  $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
   
 open (IN, "</etc/passwd");  # Do not print error messages
 my @lines=<IN>;  my $noprint=1;
 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");  
     exit 0;  
 }  
 if (@ARGV) {  
     print("Error. This program does not accept command-line arguments.\n");  
     exit 0;  
 }  
   
 # Gather input from standard input.  Should only be 3 lines.  # ----------------------------- Make sure this process is running from user=www
 my @input=<>;  my $wwwid=getpwnam('www');
 if (@input!=3) {  &disable_root_capability;
     print("Error. Three lines need to be entered into standard input.\n");  if ($wwwid!=$>) {
     exit 0;      print("User ID mismatch.  This program must be run as user 'www'\n")
    unless $noprint;
       exit 1;
 }  }
   
 # Handle case of another lcpasswd process  # ----------------------------------- Start running script with www permissions
 unless (&try_to_lock("/tmp/lock_lcpasswd")) {  &disable_root_capability;
     print "Error. Too many other simultaneous password change requests being made.\n";  
     exit 0;  
 }  
   
 my ($username,$oldpwd,$newpwd)=map {chop; $_} @input;  # --------------------------- Handle case of another lcpasswd process (locking)
   unless (&try_to_lock('/tmp/lock_lcpasswd')) {
       print "Error. Too many other simultaneous password change requests being ".
    "made.\n" unless $noprint;
       exit 4;
   }
   
 # Grab the line corresponding to username  # ------- Error-check input, need 3 values (user name, password 1, password 2).
 my ($userid,$useroldcryptpwd);  my @input;
 my @F; my @U;  @input=<>;
 for my $l (@lines) {  if (@input!=3) {
     @F=split(/\:/,$l);      print("Error. Three lines need to be entered into standard input.\n")
     if ($F[0] eq $username) {($userid,$useroldcryptpwd)=($F[2],$F[1]); @U=@F;}   unless $noprint;
       unlink('/tmp/lock_lcpasswd');
       exit 3;
   }
   foreach (@input) {chomp;}
   
   my ($username,$password1,$password2)=@input;
   $username=~/^(\w+)$/;
   my $safeusername=$1;
   if (($username ne $safeusername) or ($safeusername!~/^[A-Za-z]/)) {
       print "Error. The user name specified has invalid characters.\n";
       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";      print "Error. User $username does not exist.\n" unless $noprint;
     exit 0;      unlink('/tmp/lock_lcpasswd');
 }      exit 5;
   }
 # Verify password entry  
 if (crypt($oldpwd,$useroldcryptpwd) ne $useroldcryptpwd) {  &enable_root_capability;
     print "Error. Invalid entry of current password.\n";  ($>,$<)=(0,0);
     exit 0;  print "Now root, -invoking pwchange with $safeusername $password1"
 }      unless $noprint;
   open OUT,"|pwchange $safeusername";
 # Construct new password entry  print OUT $password1;
 my $newcryptpwd=crypt($newpwd,$newpwd);  print OUT "\n";
 $U[1]=$newcryptpwd;  close OUT;
 my $userline=join(":",@U);  ($>,$<)=(0,500);
 print $newcryptpwd;  
 print $userline;  print "pwchange done, back to uid 500" unless $noprint;
 #my $rootid=&enable_root_capability;  
 #if ($rootid!=0) {  if ($?) {
 #    print "Error.  Root was not successfully enabled.\n";      exit 8;
 #    exit 0;  }
 #}  my $userid=getpwnam($safeusername);
 # open SAMBAPASSWORDFILE, ">/etc/smbpasswd";  
  ($<,$>)=($>,$<);  if (-e '/usr/bin/smbpasswd') {
  ($(,$))=($),$();  
 open PASSWORDFILE, "/tmp/passwd2" or die("Cannot open /etc/passwd!");      ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid
 for my $l (@lines) {                     # environment
     @F=split(/\:/,$l);  
     if ($F[0] eq $username) {print PASSWORDFILE "$userline\n";}  #   If the -a swithc is put on the smbpasswd
     else {print PASSWORDFILE "$l\n";}  # command line, either a new entry will be created or the old one
   # will be used. 
   # Therefore the old strategy of looking for and adding a dummy entry is 
   # not needed... Finally, the smbpasswd file is in /etc/samba not 
   # /etc/smbpasswd as older versions of the script implied.
   
       print "Running smbpasswd" unless $noprint;
       open(OUT,"|/usr/bin/smbpasswd -s -a $safeusername>/dev/null") or
    die('cannot run smbpasswd');
       print OUT $password2; print OUT "\n";
       print OUT $password2; print OUT "\n";
       close OUT;
       $<=$wwwid; # unfool the program
       print "smbpasswd done" unless $noprint;
 }  }
 close PASSWORDFILE;  
 # close SAMBAPASSWORDFILE;  
 &disable_root_capability;  &disable_root_capability;
 unlink("/tmp/lock_lcpasswd");  unlink('/tmp/lock_lcpasswd');
   exit 0;
   
   # ---------------------------------------------- have setuid script run as root
 sub enable_root_capability {  sub enable_root_capability {
     if ($wwwid==$<) {      if ($wwwid==$>) {
  ($<,$>)=($>,$<);   ($<,$>)=($>,$<);
  ($(,$))=($),$();   ($(,$))=($),$();
     }      }
     else {      else {
  # root capability is already enabled   # root capability is already enabled
     }      }
     return $<;      return $>;
 }  }
   
   # ----------------------------------------------- have setuid script run as www
 sub disable_root_capability {  sub disable_root_capability {
     if ($wwwid==$>) {      if ($wwwid==$<) {
  ($<,$>)=($>,$<);   ($<,$>)=($>,$<);
  ($(,$))=($),$();   ($(,$))=($),$();
     }      }
Line 116  sub disable_root_capability { Line 222  sub disable_root_capability {
     }      }
 }  }
   
   # ----------------------- 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;
       # Do not manipulate lock file as root
       if ($>==0) {
    return 0;
       }
       # 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 143  sub try_to_lock { Line 259  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.1  
changed lines
  Added in v.1.17


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