Diff for /loncom/lond between versions 1.220 and 1.224

version 1.220, 2004/08/02 11:02:02 version 1.224, 2004/08/06 10:27:53
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 191  sub LocalConnection { Line 194  sub LocalConnection {
  ."$clientdns ne $thisserver </font>");   ."$clientdns ne $thisserver </font>");
  close $Socket;   close $Socket;
  return undef;   return undef;
     }       }  else {
     else {  
  chomp($initcmd); # Get rid of \n in filename.   chomp($initcmd); # Get rid of \n in filename.
  my ($init, $type, $name) = split(/:/, $initcmd);   my ($init, $type, $name) = split(/:/, $initcmd);
  Debug(" Init command: $init $type $name ");   Debug(" Init command: $init $type $name ");
Line 323  sub InsecureConnection { Line 325  sub InsecureConnection {
     $answer    =~s/\W//g;      $answer    =~s/\W//g;
     if($challenge eq $answer) {      if($challenge eq $answer) {
  return 1;   return 1;
     }       } else {
     else {  
  logthis("<font color='blue'>WARNING client did not respond to challenge</font>");   logthis("<font color='blue'>WARNING client did not respond to challenge</font>");
  &status("No challenge reqply");   &status("No challenge reqply");
  return 0;   return 0;
Line 653  sub PushFile { Line 654  sub PushFile {
  &logthis('<font color="red"> Pushfile: unable to install '   &logthis('<font color="red"> Pushfile: unable to install '
  .$tablefile." $! </font>");   .$tablefile." $! </font>");
  return "error:$!";   return "error:$!";
     }      } else {
     else {  
  &logthis('<font color="green"> Installed new '.$tablefile   &logthis('<font color="green"> Installed new '.$tablefile
  ."</font>");   ."</font>");
   
Line 1223  sub user_authorization_type { Line 1223  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 1239  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 1417  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 1623  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 1687  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 2034  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 2481  sub process_request { Line 2491  sub process_request {
  print $store2 "done\n";   print $store2 "done\n";
  close $store2;   close $store2;
  print $client "ok\n";   print $client "ok\n";
     }      } else {
     else {  
  print $client "error: ".($!+0)   print $client "error: ".($!+0)
     ." IO::File->new Failed ".      ." IO::File->new Failed ".
     "while attempting queryreply\n";      "while attempting queryreply\n";
Line 3251  sub checkchildren { Line 3260  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 3283  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 3291  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 3362  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 3675  sub make_new_child { Line 3689  sub make_new_child {
  $inittype = ""; # This forces insecure attempt.   $inittype = ""; # This forces insecure attempt.
  &logthis("<font color=\"blue\"> Certificates not "   &logthis("<font color=\"blue\"> Certificates not "
  ."installed -- trying insecure auth</font>");   ."installed -- trying insecure auth</font>");
     }      } else { # SSL certificates are in place so
     else { # SSL certificates are in place so  
     } # Leave the inittype alone.      } # Leave the inittype alone.
  }   }
   
Line 3812  sub ManagePermissions Line 3825  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.
   #
   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.
 #  #
 #   GetAuthType - Determines the authorization type of a user in a domain.  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 3838  sub GetAuthType Line 3923  sub GetAuthType
  }   }
   
  return "$authtype:$availinfo";   return "$authtype:$availinfo";
     }      } else {
     else {  
  Debug("Returning nouser");   Debug("Returning nouser");
  return "nouser";   return "nouser";
     }      }
Line 3879  sub validate_user { Line 3963  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 3919  sub validate_user { Line 4003  sub validate_user {
    $password);     $password);
  if(!$k4error) {   if(!$k4error) {
     $validated = 1;      $validated = 1;
  }   } else {
  else {  
     $validated = 0;      $validated = 0;
     &logthis('krb4: '.$user.', '.$contentpwd.', '.      &logthis('krb4: '.$user.', '.$contentpwd.', '.
      &Authen::Krb4::get_err_txt($Authen::Krb4::error));       &Authen::Krb4::get_err_txt($Authen::Krb4::error));
  }   }
     }      } else {
     else {  
  $validated = 0; # Password has a match with null.   $validated = 0; # Password has a match with null.
     }      }
  }   } elsif ($howpwd eq "krb5") { # User is in kerberos 5 auth. domain.
  elsif ($howpwd eq "krb5") { # User is in kerberos 5 auth. domain.  
     if(!($password =~ /$null/)) { # Null password not allowed.      if(!($password =~ /$null/)) { # Null password not allowed.
  my $krbclient = &Authen::Krb5::parse_name($user.'@'   my $krbclient = &Authen::Krb5::parse_name($user.'@'
   .$contentpwd);    .$contentpwd);
Line 3943  sub validate_user { Line 4024  sub validate_user {
  $password,   $password,
  $credentials);   $credentials);
  $validated = ($krbreturn == 1);   $validated = ($krbreturn == 1);
     }      } else {
     else {  
  $validated = 0;   $validated = 0;
     }      }
  }   } elsif ($howpwd eq "localauth") { 
  elsif ($howpwd eq "localauth") {   
     #  Authenticate via installation specific authentcation method:      #  Authenticate via installation specific authentcation method:
     $validated = &localauth::localauth($user,       $validated = &localauth::localauth($user, 
        $password,          $password, 
        $contentpwd);         $contentpwd);
  }   } else { # Unrecognized auth is also bad.
  else { # Unrecognized auth is also bad.  
     $validated = 0;      $validated = 0;
  }   }
     } else {      } else {
Line 4216  sub make_passwd_file { Line 4294  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  = $execdir."/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 4304  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.224


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