Diff for /loncom/lond between versions 1.220 and 1.223

version 1.220, 2004/08/02 11:02:02 version 1.223, 2004/08/05 11:37:05
Line 50  use File::Copy; Line 50  use File::Copy;
 use LONCAPA::ConfigFileEdit;  use LONCAPA::ConfigFileEdit;
 use LONCAPA::lonlocal;  use LONCAPA::lonlocal;
 use LONCAPA::lonssl;  use LONCAPA::lonssl;
   use Fcntl qw(:flock);
   
 my $DEBUG = 0;       # Non zero to enable debug log entries.  my $DEBUG = 1;       # Non zero to enable debug log entries.
   
 my $status='';  my $status='';
 my $lastlog='';  my $lastlog='';
Line 121  my @passwderrors = ("ok", Line 122  my @passwderrors = ("ok",
    "lcpasswd Cannot set new passwd.",     "lcpasswd Cannot set new passwd.",
    "lcpasswd Username has invalid characters",     "lcpasswd Username has invalid characters",
    "lcpasswd Invalid characters in password",     "lcpasswd Invalid characters in password",
     "11", "12",     "lcpasswd User already exists", 
     "lcpasswd Password mismatch");                     "lcpasswd Something went wrong with user addition.",
       "lcpasswd Password mismatch",
       "lcpasswd Error filename is invalid");
   
   
 #  The array below are lcuseradd error strings.:  #  The array below are lcuseradd error strings.:
Line 1223  sub user_authorization_type { Line 1226  sub user_authorization_type {
     my $userinput = "$cmd:$tail";      my $userinput = "$cmd:$tail";
         
     #  Pull the domain and username out of the command tail.      #  Pull the domain and username out of the command tail.
     # and call GetAuthType to determine the authentication type.      # and call get_auth_type to determine the authentication type.
         
     my ($udom,$uname)=split(/:/,$tail);      my ($udom,$uname)=split(/:/,$tail);
     my $result = &GetAuthType($udom, $uname);      my $result = &get_auth_type($udom, $uname);
     if($result eq "nouser") {      if($result eq "nouser") {
  &Failure( $replyfd, "unknown_user\n", $userinput);   &Failure( $replyfd, "unknown_user\n", $userinput);
     } else {      } else {
  #   #
  # We only want to pass the second field from GetAuthType   # We only want to pass the second field from get_auth_type
  # for ^krb.. otherwise we'll be handing out the encrypted   # for ^krb.. otherwise we'll be handing out the encrypted
  # password for internals e.g.   # password for internals e.g.
  #   #
Line 1239  sub user_authorization_type { Line 1242  sub user_authorization_type {
  if($type =~ /^krb/) {   if($type =~ /^krb/) {
     $type = $result;      $type = $result;
  }   }
  &Reply( $replyfd, "$type\n", $userinput);   &Reply( $replyfd, "$type:\n", $userinput);
     }      }
       
     return 1;      return 1;
Line 1417  sub authenticate_handler { Line 1420  sub authenticate_handler {
   
 register_handler("auth", \&authenticate_handler, 1, 1, 0);  register_handler("auth", \&authenticate_handler, 1, 1, 0);
   
   #
   #   Change a user's password.  Note that this function is complicated by
   #   the fact that a user may be authenticated in more than one way:
   #   At present, we are not able to change the password for all types of
   #   authentication methods.  Only for:
   #      unix    - unix password or shadow passoword style authentication.
   #      local   - Locally written authentication mechanism.
   #   For now, kerb4 and kerb5 password changes are not supported and result
   #   in an error.
   # FUTURE WORK:
   #    Support kerberos passwd changes?
   # Parameters:
   #    $cmd      - The command that got us here.
   #    $tail     - Tail of the command (remaining parameters).
   #    $client   - File descriptor connected to client.
   # Returns
   #     0        - Requested to exit, caller should shut down.
   #     1        - Continue processing.
   # Implicit inputs:
   #    The authentication systems describe above have their own forms of implicit
   #    input into the authentication process that are described above.
   sub change_password_handler {
       my ($cmd, $tail, $client) = @_;
   
       my $userinput = $cmd.":".$tail;           # Reconstruct client's string.
   
       #
       #  udom  - user's domain.
       #  uname - Username.
       #  upass - Current password.
       #  npass - New password.
      
       my ($udom,$uname,$upass,$npass)=split(/:/,$tail);
   
       $upass=&unescape($upass);
       $npass=&unescape($npass);
       &Debug("Trying to change password for $uname");
   
       # First require that the user can be authenticated with their
       # old password:
   
       my $validated = &validate_user($udom, $uname, $upass);
       if($validated) {
    my $realpasswd  = &get_auth_type($udom, $uname); # Defined since authd.
   
    my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
    if ($howpwd eq 'internal') {
       &Debug("internal auth");
       my $salt=time;
       $salt=substr($salt,6,2);
       my $ncpass=crypt($npass,$salt);
       if(&rewrite_password_file($udom, $uname, "internal:$ncpass")) {
    &logthis("Result of password change for "
    ."$uname: pwchange_success");
    &Reply($client, "ok\n", $userinput);
       } else {
    &logthis("Unable to open $uname passwd "               
    ."to change password");
    &Failure( $client, "non_authorized\n",$userinput);
       }
    } elsif ($howpwd eq 'unix') {
       # Unix means we have to access /etc/password
       &Debug("auth is unix");
       my $execdir=$perlvar{'lonDaemons'};
       &Debug("Opening lcpasswd pipeline");
       my $pf = IO::File->new("|$execdir/lcpasswd > "
      ."$perlvar{'lonDaemons'}"
      ."/logs/lcpasswd.log");
       print $pf "$uname\n$npass\n$npass\n";
       close $pf;
       my $err = $?;
       my $result = ($err>0 ? 'pwchange_failure' : 'ok');
       &logthis("Result of password change for $uname: ".
        &lcpasswdstrerror($?));
       &Reply($client, "$result\n", $userinput);
    } else {
       # this just means that the current password mode is not
       # one we know how to change (e.g the kerberos auth modes or
       # locally written auth handler).
       #
       &Failure( $client, "auth_mode_error\n", $userinput);
    }  
   
       }
       else {
    &Failure( $client, "non_authorized\n", $userinput);
       }
   
       return 1;
   }
   register_handler("passwd", \&change_password_handler, 1, 1, 0);
   
   
 #---------------------------------------------------------------  #---------------------------------------------------------------
 #  #
 #   Getting, decoding and dispatching requests:  #   Getting, decoding and dispatching requests:
Line 1531  sub process_request { Line 1627  sub process_request {
 #------------------- Commands not yet in spearate handlers. --------------  #------------------- Commands not yet in spearate handlers. --------------
   
   
 # ---------------------------------------------------------------------- passwd  
     if ($userinput =~ /^passwd/) { # encoded and client  
  if (($wasenc==1) && isClient) {  
     my   
  ($cmd,$udom,$uname,$upass,$npass)=split(/:/,$userinput);  
     chomp($npass);  
     $upass=&unescape($upass);  
     $npass=&unescape($npass);  
     &Debug("Trying to change password for $uname");  
     my $proname=propath($udom,$uname);  
     my $passfilename="$proname/passwd";  
     if (-e $passfilename) {  
  my $realpasswd;  
  { my $pf = IO::File->new($passfilename);  
   $realpasswd=<$pf>; }  
  chomp($realpasswd);  
  my ($howpwd,$contentpwd)=split(/:/,$realpasswd);  
  if ($howpwd eq 'internal') {  
     &Debug("internal auth");  
     if (crypt($upass,$contentpwd) eq $contentpwd) {  
  my $salt=time;  
  $salt=substr($salt,6,2);  
  my $ncpass=crypt($npass,$salt);  
  {  
     my $pf;  
     if ($pf = IO::File->new(">$passfilename")) {  
  print $pf "internal:$ncpass\n";  
  &logthis("Result of password change for $uname: pwchange_success");  
  print $client "ok\n";  
     } else {  
  &logthis("Unable to open $uname passwd to change password");  
  print $client "non_authorized\n";  
     }  
  }               
   
     } else {  
  print $client "non_authorized\n";  
     }  
  } elsif ($howpwd eq 'unix') {  
     # Unix means we have to access /etc/password  
     # one way or another.  
     # First: Make sure the current password is  
     #        correct  
     &Debug("auth is unix");  
     $contentpwd=(getpwnam($uname))[1];  
     my $pwdcorrect = "0";  
     my $pwauth_path="/usr/local/sbin/pwauth";  
     unless ($contentpwd eq 'x') {  
  $pwdcorrect=  
     (crypt($upass,$contentpwd) eq $contentpwd);  
     } elsif (-e $pwauth_path) {  
  open PWAUTH, "|$pwauth_path" or  
     die "Cannot invoke authentication";  
  print PWAUTH "$uname\n$upass\n";  
  close PWAUTH;  
  &Debug("exited pwauth with $? ($uname,$upass) ");  
  $pwdcorrect=($? == 0);  
     }  
     if ($pwdcorrect) {  
  my $execdir=$perlvar{'lonDaemons'};  
  &Debug("Opening lcpasswd pipeline");  
  my $pf = IO::File->new("|$execdir/lcpasswd > $perlvar{'lonDaemons'}/logs/lcpasswd.log");  
  print $pf "$uname\n$npass\n$npass\n";  
  close $pf;  
  my $err = $?;  
  my $result = ($err>0 ? 'pwchange_failure'   
       : 'ok');  
  &logthis("Result of password change for $uname: ".  
  &lcpasswdstrerror($?));  
  print $client "$result\n";  
     } else {  
  print $client "non_authorized\n";  
     }  
  } else {  
     print $client "auth_mode_error\n";  
  }    
     } else {  
  print $client "unknown_user\n";  
     }  
  } else {  
     Reply($client, "refused\n", $userinput);  
       
  }  
 # -------------------------------------------------------------------- makeuser  # -------------------------------------------------------------------- makeuser
     } elsif ($userinput =~ /^makeuser/) { # encoded and client.      if ($userinput =~ /^makeuser/) { # encoded and client.
  &Debug("Make user received");   &Debug("Make user received");
  my $oldumask=umask(0077);   my $oldumask=umask(0077);
  if (($wasenc==1) && isClient) {   if (($wasenc==1) && isClient) {
Line 1677  sub process_request { Line 1691  sub process_request {
     } else {      } else {
  my $result=&make_passwd_file($uname, $umode,$npass,   my $result=&make_passwd_file($uname, $umode,$npass,
      $passfilename);       $passfilename);
  print $client $result;   Reply($client, $result, $userinput);
     }      }
  } else {   } else {
     Reply($client, "refused\n", $userinput);      Reply($client, "refused\n", $userinput);
Line 2024  sub process_request { Line 2038  sub process_request {
     foreach my $pair (@pairs) {      foreach my $pair (@pairs) {
  my ($key,$value)=split(/=/,$pair);   my ($key,$value)=split(/=/,$pair);
  &ManagePermissions($key, $udom, $uname,   &ManagePermissions($key, $udom, $uname,
    &GetAuthType( $udom,      &get_auth_type( $udom, 
  $uname));   $uname));
  $hash{$key}=$value;   $hash{$key}=$value;
     }      }
Line 3251  sub checkchildren { Line 3265  sub checkchildren {
     &logthis('Going to check on the children');      &logthis('Going to check on the children');
     my $docdir=$perlvar{'lonDocRoot'};      my $docdir=$perlvar{'lonDocRoot'};
     foreach (sort keys %children) {      foreach (sort keys %children) {
  sleep 1;   #sleep 1;
         unless (kill 'USR1' => $_) {          unless (kill 'USR1' => $_) {
     &logthis ('Child '.$_.' is dead');      &logthis ('Child '.$_.' is dead');
             &logstatus($$.' is dead');              &logstatus($$.' is dead');
       delete($children{$_});
         }           } 
     }      }
     sleep 5;      sleep 5;
Line 3273  sub checkchildren { Line 3288  sub checkchildren {
     #my $result=`echo 'Killed lond process $_.' | mailto $emailto -s '$subj' > /dev/null`;      #my $result=`echo 'Killed lond process $_.' | mailto $emailto -s '$subj' > /dev/null`;
     #$execdir=$perlvar{'lonDaemons'};      #$execdir=$perlvar{'lonDaemons'};
     #$result=`/bin/cp $execdir/logs/lond.log $execdir/logs/lond.log.$_`;      #$result=`/bin/cp $execdir/logs/lond.log $execdir/logs/lond.log.$_`;
       delete($children{$_});
     alarm(0);      alarm(0);
   }    }
         }          }
Line 3280  sub checkchildren { Line 3296  sub checkchildren {
     $SIG{ALRM} = 'DEFAULT';      $SIG{ALRM} = 'DEFAULT';
     $SIG{__DIE__} = \&catchexception;      $SIG{__DIE__} = \&catchexception;
     &status("Finished checking children");      &status("Finished checking children");
       &logthis('Finished Checking children');
 }  }
   
 # --------------------------------------------------------------------- Logging  # --------------------------------------------------------------------- Logging
Line 3350  sub logstatus { Line 3367  sub logstatus {
     &status("Doing logging");      &status("Doing logging");
     my $docdir=$perlvar{'lonDocRoot'};      my $docdir=$perlvar{'lonDocRoot'};
     {      {
     my $fh=IO::File->new(">>$docdir/lon-status/londstatus.txt");  
     print $fh $$."\t".$clientname."\t".$currenthostid."\t"  
  .$status."\t".$lastlog."\t $keymode\n";  
     $fh->close();  
     }  
     &status("Finished londstatus.txt");  
     {  
  my $fh=IO::File->new(">$docdir/lon-status/londchld/$$.txt");   my $fh=IO::File->new(">$docdir/lon-status/londchld/$$.txt");
         print $fh $status."\n".$lastlog."\n".time."\n$keymode";          print $fh $status."\n".$lastlog."\n".time."\n$keymode";
         $fh->close();          $fh->close();
     }      }
       &status("Finished $$.txt");
       {
    open(LOG,">>$docdir/lon-status/londstatus.txt");
    flock(LOG,LOCK_EX);
    print LOG $$."\t".$clientname."\t".$currenthostid."\t"
       .$status."\t".$lastlog."\t $keymode\n";
    flock(DB,LOCK_UN);
    close(LOG);
       }
     &status("Finished logging");      &status("Finished logging");
 }  }
   
Line 3812  sub ManagePermissions Line 3831  sub ManagePermissions
  system("$execdir/lchtmldir $userhome $user $authtype");   system("$execdir/lchtmldir $userhome $user $authtype");
     }      }
 }  }
   
   
   #
   #  Return the full path of a user password file, whether it exists or not.
   # Parameters:
   #   domain     - Domain in which the password file lives.
   #   user       - name of the user.
   # Returns:
   #    Full passwd path:
   #
   sub password_path {
       my ($domain, $user) = @_;
   
   
       my $path   = &propath($domain, $user);
       $path  .= "/passwd";
   
       return $path;
   }
   
   #   Password Filename
   #   Returns the path to a passwd file given domain and user... only if
   #  it exists.
   # Parameters:
   #   domain    - Domain in which to search.
   #   user      - username.
   # Returns:
   #   - If the password file exists returns its path.
   #   - If the password file does not exist, returns undefined.
 #  #
 #   GetAuthType - Determines the authorization type of a user in a domain.  sub password_filename {
       my ($domain, $user) = @_;
   
       Debug ("PasswordFilename called: dom = $domain user = $user");
   
       my $path  = &password_path($domain, $user);
       Debug("PasswordFilename got path: $path");
       if(-e $path) {
    return $path;
       } else {
    return undef;
       }
   }
   
   #
   #   Rewrite the contents of the user's passwd file.
   #  Parameters:
   #    domain    - domain of the user.
   #    name      - User's name.
   #    contents  - New contents of the file.
   # Returns:
   #   0    - Failed.
   #   1    - Success.
   #
   sub rewrite_password_file {
       my ($domain, $user, $contents) = @_;
   
       my $file = &password_filename($domain, $user);
       if (defined $file) {
    my $pf = IO::File->new(">$file");
    if($pf) {
       print $pf "$contents\n";
       return 1;
    } else {
       return 0;
    }
       } else {
    return 0;
       }
   
   }
   
   #
   #   get_auth_type - Determines the authorization type of a user in a domain.
   
 #     Returns the authorization type or nouser if there is no such user.  #     Returns the authorization type or nouser if there is no such user.
 #  #
 sub GetAuthType   sub get_auth_type 
 {  {
   
     my ($domain, $user)  = @_;      my ($domain, $user)  = @_;
   
     Debug("GetAuthType( $domain, $user ) \n");      Debug("get_auth_type( $domain, $user ) \n");
     my $proname    = &propath($domain, $user);       my $proname    = &propath($domain, $user); 
     my $passwdfile = "$proname/passwd";      my $passwdfile = "$proname/passwd";
     if( -e $passwdfile ) {      if( -e $passwdfile ) {
Line 3879  sub validate_user { Line 3970  sub validate_user {
     #  the user has been assigned.  If the authentication type is      #  the user has been assigned.  If the authentication type is
     #  "nouser", the user does not exist so we will return 0.      #  "nouser", the user does not exist so we will return 0.
   
     my $contents = &GetAuthType($domain, $user);      my $contents = &get_auth_type($domain, $user);
     my ($howpwd, $contentpwd) = split(/:/, $contents);      my ($howpwd, $contentpwd) = split(/:/, $contents);
   
     my $null = pack("C",0); # Used by kerberos auth types.      my $null = pack("C",0); # Used by kerberos auth types.
Line 4216  sub make_passwd_file { Line 4307  sub make_passwd_file {
  return "no_priv_account_error\n";   return "no_priv_account_error\n";
     }      }
   
     my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd";      my $execpath       ="$perlvar{'lonDaemons'}/"."lcuseradd";
       my $lc_error_file  = "/tmp/lcuseradd".$$.".status";
     {      {
  &Debug("Executing external: ".$execpath);   &Debug("Executing external: ".$execpath);
  &Debug("user  = ".$uname.", Password =". $npass);   &Debug("user  = ".$uname.", Password =". $npass);
Line 4224  sub make_passwd_file { Line 4316  sub make_passwd_file {
  print $se "$uname\n";   print $se "$uname\n";
  print $se "$npass\n";   print $se "$npass\n";
  print $se "$npass\n";   print $se "$npass\n";
    print $se "$lc_error_file\n"; # Status -> unique file.
     }      }
     my $useraddok = $?;      my $error = IO::File->new("< $lc_error_file");
       my $useraddok = <$error>;
       $error->close;
       unlink($lc_error_file);
   
       chomp $useraddok;
   
     if($useraddok > 0) {      if($useraddok > 0) {
  &logthis("Failed lcuseradd: ".&lcuseraddstrerror($useraddok));   my $error_text = &lcuseraddstrerror($useraddok);
    &logthis("Failed lcuseradd: $error_text");
    $result = "lcuseradd_failed:$error_text\n";
       }
       else {
    my $pf = IO::File->new(">$passfilename");
    print $pf "unix:\n";
     }      }
     my $pf = IO::File->new(">$passfilename");  
     print $pf "unix:\n";  
  }   }
     } elsif ($umode eq 'none') {      } elsif ($umode eq 'none') {
  {   {
     my $pf = IO::File->new(">$passfilename");      my $pf = IO::File->new("> $passfilename");
     print $pf "none:\n";      print $pf "none:\n";
  }   }
     } else {      } else {

Removed from v.1.220  
changed lines
  Added in v.1.223


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