Diff for /loncom/lond between versions 1.73 and 1.80

version 1.73, 2002/02/25 20:43:15 version 1.80, 2002/05/11 21:24:56
Line 53 Line 53
 # 02/12 Gerd Kortemeyer  # 02/12 Gerd Kortemeyer
 # 02/19 Matthew Hall  # 02/19 Matthew Hall
 # 02/25 Gerd Kortemeyer  # 02/25 Gerd Kortemeyer
   # 05/11 Scott Harrison
 ###  ###
   
 # based on "Perl Cookbook" ISBN 1-56592-243-3  # based on "Perl Cookbook" ISBN 1-56592-243-3
Line 61 Line 62
 # HUPs  # HUPs
 # uses IDEA encryption  # uses IDEA encryption
   
   use lib '/home/httpd/lib/perl/';
   use LONCAPA::Configuration;
   
 use IO::Socket;  use IO::Socket;
 use IO::File;  use IO::File;
 use Apache::File;  use Apache::File;
Line 73  use Authen::Krb4; Line 77  use Authen::Krb4;
 use lib '/home/httpd/lib/perl/';  use lib '/home/httpd/lib/perl/';
 use localauth;  use localauth;
   
   my $DEBUG = 0;       # Non zero to enable debug log entries.
   
 my $status='';  my $status='';
 my $lastlog='';  my $lastlog='';
   
Line 99  sub timeout { Line 105  sub timeout {
 $SIG{'QUIT'}=\&catchexception;  $SIG{'QUIT'}=\&catchexception;
 $SIG{__DIE__}=\&catchexception;  $SIG{__DIE__}=\&catchexception;
   
 # ------------------------------------ Read httpd access.conf and get variables  # ------------------------------------------- Read access.conf and loncapa.conf
   &status("Read access.conf and loncapa.conf");
 open (CONFIG,"/etc/httpd/conf/access.conf") || die "Can't read access.conf";  my $perlvarref=LONCAPA::Configuration::read_conf('access.conf','loncapa.conf');
   my %perlvar=%{$perlvarref};
 while ($configline=<CONFIG>) {  undef $perlvarref;
     if ($configline =~ /PerlSetVar/) {  
  my ($dummy,$varname,$varvalue)=split(/\s+/,$configline);  
         chomp($varvalue);  
         $perlvar{$varname}=$varvalue;  
     }  
 }  
 close(CONFIG);  
   
 # ----------------------------- Make sure this process is running from user=www  # ----------------------------- Make sure this process is running from user=www
 my $wwwid=getpwnam('www');  my $wwwid=getpwnam('www');
Line 160  $server = IO::Socket::INET->new(LocalPor Line 159  $server = IO::Socket::INET->new(LocalPor
   
 # global variables  # global variables
   
 $MAX_CLIENTS_PER_CHILD  = 5;        # number of clients each child should   $MAX_CLIENTS_PER_CHILD  = 50;        # number of clients each child should 
                                     # process                                      # process
 %children               = ();       # keys are current child process IDs  %children               = ();       # keys are current child process IDs
 $children               = 0;        # current number of children  $children               = 0;        # current number of children
Line 235  sub logthis { Line 234  sub logthis {
     print $fh "$local ($$): $message\n";      print $fh "$local ($$): $message\n";
 }  }
   
   # ------------------------- Conditional log if $DEBUG true.
   sub Debug {
       my $message = shift;
       if($DEBUG) {
    &logthis($message);
       }
   }
 # ------------------------------------------------------------------ Log status  # ------------------------------------------------------------------ Log status
   
 sub logstatus {  sub logstatus {
Line 301  sub reconlonc { Line 307  sub reconlonc {
         if (kill 0 => $loncpid) {          if (kill 0 => $loncpid) {
     &logthis("lonc at pid $loncpid responding, sending USR1");      &logthis("lonc at pid $loncpid responding, sending USR1");
             kill USR1 => $loncpid;              kill USR1 => $loncpid;
             sleep 1;              sleep 5;
             if (-e "$peerfile") { return; }              if (-e "$peerfile") { return; }
             &logthis("$peerfile still not there, give it another try");              &logthis("$peerfile still not there, give it another try");
             sleep 5;              sleep 10;
             if (-e "$peerfile") { return; }              if (-e "$peerfile") { return; }
             &logthis(              &logthis(
  "<font color=blue>WARNING: $peerfile still not there, giving up</font>");   "<font color=blue>WARNING: $peerfile still not there, giving up</font>");
Line 342  sub reply { Line 348  sub reply {
     if ($answer eq 'con_lost') {      if ($answer eq 'con_lost') {
  $answer=subreply("ping",$server);   $answer=subreply("ping",$server);
         if ($answer ne $server) {          if ($answer ne $server) {
       &logthis("sub reply: answer != server");
            &reconlonc("$perlvar{'lonSockDir'}/$server");             &reconlonc("$perlvar{'lonSockDir'}/$server");
         }          }
         $answer=subreply($cmd,$server);          $answer=subreply($cmd,$server);
Line 531  sub make_new_child { Line 538  sub make_new_child {
             }              }
             if ($clientok) {              if ($clientok) {
 # ---------------- New known client connecting, could mean machine online again  # ---------------- New known client connecting, could mean machine online again
   
       &reconlonc("$perlvar{'lonSockDir'}/$hostid{$clientip}");        &reconlonc("$perlvar{'lonSockDir'}/$hostid{$clientip}");
               &logthis(                &logthis(
        "<font color=green>Established connection: $hostid{$clientip}</font>");         "<font color=green>Established connection: $hostid{$clientip}</font>");
Line 538  sub make_new_child { Line 546  sub make_new_child {
 # ------------------------------------------------------------ Process requests  # ------------------------------------------------------------ Process requests
               while (my $userinput=<$client>) {                while (my $userinput=<$client>) {
                 chomp($userinput);                  chomp($userinput);
    Debug("Request = $userinput\n");
                 &status('Processing '.$hostid{$clientip}.': '.$userinput);                  &status('Processing '.$hostid{$clientip}.': '.$userinput);
                 my $wasenc=0;                  my $wasenc=0;
                 alarm(120);                  alarm(120);
Line 554  sub make_new_child { Line 563  sub make_new_child {
     }      }
     $userinput=substr($userinput,0,$cmdlength);      $userinput=substr($userinput,0,$cmdlength);
                     $wasenc=1;                      $wasenc=1;
   }  
  }   }
         }
     
 # ------------------------------------------------------------- Normal commands  # ------------------------------------------------------------- Normal commands
 # ------------------------------------------------------------------------ ping  # ------------------------------------------------------------------------ ping
    if ($userinput =~ /^ping/) {     if ($userinput =~ /^ping/) {
Line 592  sub make_new_child { Line 602  sub make_new_child {
    } elsif ($userinput =~ /^currentauth/) {     } elsif ($userinput =~ /^currentauth/) {
      if ($wasenc==1) {       if ($wasenc==1) {
                        my ($cmd,$udom,$uname)=split(/:/,$userinput);                         my ($cmd,$udom,$uname)=split(/:/,$userinput);
                        my $proname=propath($udom,$uname);         my $result = GetAuthType($udom, $uname);
                        my $passfilename="$proname/passwd";         if($result eq "nouser") {
                        if (-e $passfilename) {     print $client "unknown_user\n";
    my $pf = IO::File->new($passfilename);         }
    my $realpasswd=<$pf>;         else {
    chomp($realpasswd);     print $client "$result\n"
    my ($howpwd,$contentpwd)=split(/:/,$realpasswd);         }
    my $availablecontent='';  
    if ($howpwd eq 'krb4') {  
        $availablecontent=$contentpwd;  
    }  
    print $client "$howpwd:$availablecontent\n";  
        } else {  
                           print $client "unknown_user\n";  
                        }  
      } else {       } else {
        print $client "refused\n";         print $client "refused\n";
      }       }
Line 734  sub make_new_child { Line 736  sub make_new_child {
      }       }
 # -------------------------------------------------------------------- makeuser  # -------------------------------------------------------------------- makeuser
                    } elsif ($userinput =~ /^makeuser/) {                     } elsif ($userinput =~ /^makeuser/) {
        Debug("Make user received");
                 my $oldumask=umask(0077);                  my $oldumask=umask(0077);
      if ($wasenc==1) {       if ($wasenc==1) {
                        my                          my 
                        ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);                         ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);
          &Debug("cmd =".$cmd." $udom =".$udom.
       " uname=".$uname);
                        chomp($npass);                         chomp($npass);
                        $npass=&unescape($npass);                         $npass=&unescape($npass);
                        my $proname=propath($udom,$uname);                         my $proname=propath($udom,$uname);
                        my $passfilename="$proname/passwd";                         my $passfilename="$proname/passwd";
          &Debug("Password file created will be:".
       $passfilename);
                        if (-e $passfilename) {                         if (-e $passfilename) {
    print $client "already_exists\n";     print $client "already_exists\n";
                        } elsif ($udom ne $perlvar{'lonDefDomain'}) {                         } elsif ($udom ne $perlvar{'lonDefDomain'}) {
Line 770  sub make_new_child { Line 777  sub make_new_child {
                                $salt=substr($salt,6,2);                                 $salt=substr($salt,6,2);
        my $ncpass=crypt($npass,$salt);         my $ncpass=crypt($npass,$salt);
                                {                                  { 
                                  my $pf = IO::File->new(">$passfilename");   &Debug("Creating internal auth");
    my $pf = IO::File->new(">$passfilename");
             print $pf "internal:$ncpass\n";               print $pf "internal:$ncpass\n"; 
                                }                                 }
                                print $client "ok\n";                                 print $client "ok\n";
Line 785  sub make_new_child { Line 793  sub make_new_child {
  my $execpath="$perlvar{'lonDaemons'}/".   my $execpath="$perlvar{'lonDaemons'}/".
               "lcuseradd";                "lcuseradd";
  {   {
        &Debug("Executing external: ".
     $execpath);
      my $se = IO::File->new("|$execpath");       my $se = IO::File->new("|$execpath");
      print $se "$uname\n";       print $se "$uname\n";
      print $se "$npass\n";       print $se "$npass\n";
Line 813  sub make_new_child { Line 823  sub make_new_child {
      umask($oldumask);       umask($oldumask);
 # -------------------------------------------------------------- changeuserauth  # -------------------------------------------------------------- changeuserauth
                    } elsif ($userinput =~ /^changeuserauth/) {                     } elsif ($userinput =~ /^changeuserauth/) {
      if ($wasenc==1) {         &Debug("Changing authorization");
         if ($wasenc==1) {
                        my                          my 
                        ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);                         ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);
                        chomp($npass);                         chomp($npass);
          &Debug("cmd = ".$cmd." domain= ".$udom.
         "uname =".$uname." umode= ".$umode);
                        $npass=&unescape($npass);                         $npass=&unescape($npass);
                        my $proname=propath($udom,$uname);                         my $proname=propath($udom,$uname);
                        my $passfilename="$proname/passwd";                         my $passfilename="$proname/passwd";
Line 1025  sub make_new_child { Line 1038  sub make_new_child {
                       }                        }
 # -------------------------------------------------------------------- rolesput  # -------------------------------------------------------------------- rolesput
                    } elsif ($userinput =~ /^rolesput/) {                     } elsif ($userinput =~ /^rolesput/) {
          &Debug("rolesput");
     if ($wasenc==1) {      if ($wasenc==1) {
                        my ($cmd,$exedom,$exeuser,$udom,$uname,$what)                         my ($cmd,$exedom,$exeuser,$udom,$uname,$what)
                           =split(/:/,$userinput);                            =split(/:/,$userinput);
          &Debug("cmd = ".$cmd." exedom= ".$exedom.
       "user = ".$exeuser." udom=".$udom.
       "what = ".$what);
                        my $namespace='roles';                         my $namespace='roles';
                        chomp($what);                         chomp($what);
                        my $proname=propath($udom,$uname);                         my $proname=propath($udom,$uname);
Line 1044  sub make_new_child { Line 1061  sub make_new_child {
       if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT,0640)) {
                            foreach $pair (@pairs) {                             foreach $pair (@pairs) {
        ($key,$value)=split(/=/,$pair);         ($key,$value)=split(/=/,$pair);
          &ManagePermissions($key, $udom, $uname,
     &GetAuthType( $udom, 
    $uname));
                                $hash{$key}=$value;                                 $hash{$key}=$value;
          
                            }                             }
    if (untie(%hash)) {     if (untie(%hash)) {
                               print $client "ok\n";                                print $client "ok\n";
Line 1421  sub make_new_child { Line 1442  sub make_new_child {
                 $client->close();                  $client->close();
                 &logthis("<font color=blue>WARNING: "                  &logthis("<font color=blue>WARNING: "
                 ."Rejected client $clientip, closing connection</font>");                  ."Rejected client $clientip, closing connection</font>");
             }                            }
             &logthis("<font color=red>CRITICAL: "   }              
                     ."Disconnect from $clientip ($hostid{$clientip})</font>");  
 # =============================================================================  # =============================================================================
         }         
        &logthis("<font color=red>CRITICAL: "
    ."Disconnect from $clientip ($hostid{$clientip})</font>");    
         # tidy up gracefully and finish          # tidy up gracefully and finish
           
         $server->close();          $server->close();
Line 1438  sub make_new_child { Line 1460  sub make_new_child {
     }      }
 }  }
   
   
   #
   #   Checks to see if the input roleput request was to set
   # an author role.  If so, invokes the lchtmldir script to set
   # up a correct public_html 
   # Parameters:
   #    request   - The request sent to the rolesput subchunk.
   #                We're looking for  /domain/_au
   #    domain    - The domain in which the user is having roles doctored.
   #    user      - Name of the user for which the role is being put.
   #    authtype  - The authentication type associated with the user.
   #
   sub ManagePermissions
   {
       my $request = shift;
       my $domain  = shift;
       my $user    = shift;
       my $authtype= shift;
   
       # See if the request is of the form /$domain/_au
   
       if($request =~ /^(\/$domain\/_au)$/) { # It's an author rolesput...
    my $execdir = $perlvar{'lonDaemons'};
    my $userhome= "/home/$user" ;
    Debug("system $execdir/lchtmldir $userhome $system $authtype");
    system("$execdir/lchtmldir $userhome $user $authtype");
       }
   }
   #
   #   GetAuthType - Determines the authorization type of a user in a domain.
   
   #     Returns the authorization type or nouser if there is no such user.
   #
   sub GetAuthType 
   {
       my $domain = shift;
       my $user   = shift;
   
       Debug("GetAuthType( $domain, $user ) \n");
       my $proname    = &propath($domain, $user); 
       my $passwdfile = "$proname/passwd";
       if( -e $passwdfile ) {
    my $pf = IO::File->new($passwdfile);
    my $realpassword = <$pf>;
    chomp($realpassword);
    Debug("Password info = $realpassword\n");
    my ($authtype, $contentpwd) = split(/:/, $realpassword);
    Debug("Authtype = $authtype, content = $contentpwd\n");
    my $availinfo = '';
    if($authtype eq 'krb4') {
       $availinfo = $contentpwd;
    }
   
    return "$authtype:$availinfo";
       }
       else {
    Debug("Returning nouser");
    return "nouser";
       }
       
   }
   
 # ----------------------------------- POD (plain old documentation, CPAN style)  # ----------------------------------- POD (plain old documentation, CPAN style)
   
 =head1 NAME  =head1 NAME
Line 1446  lond - "LON Daemon" Server (port "LOND" Line 1530  lond - "LON Daemon" Server (port "LOND"
   
 =head1 SYNOPSIS  =head1 SYNOPSIS
   
 Should only be run as user=www.  Invoked by loncron.  Usage: B<lond>
   
   Should only be run as user=www.  This is a command-line script which
   is invoked by B<loncron>.  There is no expectation that a typical user
   will manually start B<lond> from the command-line.  (In other words,
   DO NOT START B<lond> YOURSELF.)
   
 =head1 DESCRIPTION  =head1 DESCRIPTION
   
   There are two characteristics associated with the running of B<lond>,
   PROCESS MANAGEMENT (starting, stopping, handling child processes)
   and SERVER-SIDE ACTIVITIES (password authentication, user creation,
   subscriptions, etc).  These are described in two large
   sections below.
   
   B<PROCESS MANAGEMENT>
   
 Preforker - server who forks first. Runs as a daemon. HUPs.  Preforker - server who forks first. Runs as a daemon. HUPs.
 Uses IDEA encryption  Uses IDEA encryption
   
 =head1 README  B<lond> forks off children processes that correspond to the other servers
   in the network.  Management of these processes can be done at the
   parent process level or the child process level.
   
   B<logs/lond.log> is the location of log messages.
   
   The process management is now explained in terms of linux shell commands,
   subroutines internal to this code, and signal assignments:
   
   =over 4
   
   =item *
   
   PID is stored in B<logs/lond.pid>
   
   This is the process id number of the parent B<lond> process.
   
   =item *
   
   SIGTERM and SIGINT
   
   Parent signal assignment:
    $SIG{INT}  = $SIG{TERM} = \&HUNTSMAN;
   
   Child signal assignment:
    $SIG{INT}  = 'DEFAULT'; (and SIGTERM is DEFAULT also)
   (The child dies and a SIGALRM is sent to parent, awaking parent from slumber
    to restart a new child.)
   
   Command-line invocations:
    B<kill> B<-s> SIGTERM I<PID>
    B<kill> B<-s> SIGINT I<PID>
   
   Subroutine B<HUNTSMAN>:
    This is only invoked for the B<lond> parent I<PID>.
   This kills all the children, and then the parent.
   The B<lonc.pid> file is cleared.
   
   =item *
   
   SIGHUP
   
   Current bug:
    This signal can only be processed the first time
   on the parent process.  Subsequent SIGHUP signals
   have no effect.
   
   Parent signal assignment:
    $SIG{HUP}  = \&HUPSMAN;
   
   Child signal assignment:
    none (nothing happens)
   
   Command-line invocations:
    B<kill> B<-s> SIGHUP I<PID>
   
   Subroutine B<HUPSMAN>:
    This is only invoked for the B<lond> parent I<PID>,
   This kills all the children, and then the parent.
   The B<lond.pid> file is cleared.
   
   =item *
   
   SIGUSR1
   
   Parent signal assignment:
    $SIG{USR1} = \&USRMAN;
   
   Child signal assignment:
    $SIG{USR1}= \&logstatus;
   
   Command-line invocations:
    B<kill> B<-s> SIGUSR1 I<PID>
   
   Subroutine B<USRMAN>:
    When invoked for the B<lond> parent I<PID>,
   SIGUSR1 is sent to all the children, and the status of
   each connection is logged.
   
   =item *
   
   SIGCHLD
   
   Parent signal assignment:
    $SIG{CHLD} = \&REAPER;
   
   Child signal assignment:
    none
   
   Command-line invocations:
    B<kill> B<-s> SIGCHLD I<PID>
   
   Subroutine B<REAPER>:
    This is only invoked for the B<lond> parent I<PID>.
   Information pertaining to the child is removed.
   The socket port is cleaned up.
   
   =back
   
   B<SERVER-SIDE ACTIVITIES>
   
   Server-side information can be accepted in an encrypted or non-encrypted
   method.
   
 Not yet written.  =over 4
   
   =item ping
   
   Query a client in the hosts.tab table; "Are you there?"
   
   =item pong
   
   Respond to a ping query.
   
   =item ekey
   
   Read in encrypted key, make cipher.  Respond with a buildkey.
   
   =item load
   
   Respond with CPU load based on a computation upon /proc/loadavg.
   
   =item currentauth
   
   Reply with current authentication information (only over an
   encrypted channel).
   
   =item auth
   
   Only over an encrypted channel, reply as to whether a user's
   authentication information can be validated.
   
   =item passwd
   
   Allow for a password to be set.
   
   =item makeuser
   
   Make a user.
   
   =item passwd
   
   Allow for authentication mechanism and password to be changed.
   
   =item home
   
   Respond to a question "are you the home for a given user?"
   
   =item update
   
   Update contents of a subscribed resource.
   
   =item unsubscribe
   
   The server is unsubscribing from a resource.
   
   =item subscribe
   
   The server is subscribing to a resource.
   
   =item log
   
   Place in B<logs/lond.log>
   
   =item put
   
   stores hash in namespace
   
   =item rolesput
   
   put a role into a user's environment
   
   =item get
   
   returns hash with keys from array
   reference filled in from namespace
   
   =item eget
   
   returns hash with keys from array
   reference filled in from namesp (encrypts the return communication)
   
   =item rolesget
   
   get a role from a user's environment
   
   =item del
   
   deletes keys out of array from namespace
   
   =item keys
   
   returns namespace keys
   
   =item dump
   
   dumps the complete (or key matching regexp) namespace into a hash
   
   =item store
   
   stores hash permanently
   for this url; hashref needs to be given and should be a \%hashname; the
   remaining args aren't required and if they aren't passed or are '' they will
   be derived from the ENV
   
   =item restore
   
   returns a hash for a given url
   
   =item querysend
   
   Tells client about the lonsql process that has been launched in response
   to a sent query.
   
   =item queryreply
   
   Accept information from lonsql and make appropriate storage in temporary
   file space.
   
   =item idput
   
   Defines usernames as corresponding to IDs.  (These "IDs" are unique identifiers
   for each student, defined perhaps by the institutional Registrar.)
   
   =item idget
   
   Returns usernames corresponding to IDs.  (These "IDs" are unique identifiers
   for each student, defined perhaps by the institutional Registrar.)
   
   =item tmpput
   
   Accept and store information in temporary space.
   
   =item tmpget
   
   Send along temporarily stored information.
   
   =item ls
   
   List part of a user's directory.
   
   =item Hanging up (exit or init)
   
   What to do when a client tells the server that they (the client)
   are leaving the network.
   
   =item unknown command
   
   If B<lond> is sent an unknown command (not in the list above),
   it replys to the client "unknown_cmd".
   
   =item UNKNOWN CLIENT
   
   If the anti-spoofing algorithm cannot verify the client,
   the client is rejected (with a "refused" message sent
   to the client, and the connection is closed.
   
   =back
   
 =head1 PREREQUISITES  =head1 PREREQUISITES
   
Line 1480  linux Line 1832  linux
 Server/Process  Server/Process
   
 =cut  =cut
   
   
   
   
   
   
   
   

Removed from v.1.73  
changed lines
  Added in v.1.80


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.