Diff for /loncom/lond between versions 1.153 and 1.211

version 1.153, 2003/10/08 14:30:09 version 1.211, 2004/07/23 16:14:19
Line 10 Line 10
 #  #
 # LON-CAPA is free software; you can redistribute it and/or modify  # LON-CAPA is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by  # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 2 of the License, or  # the Free Software Foundation; either version 2 of the License, or 
 # (at your option) any later version.  # (at your option) any later version.
 #  #
 # LON-CAPA is distributed in the hope that it will be useful,  # LON-CAPA is distributed in the hope that it will be useful,
Line 24 Line 24
 #  #
 # /home/httpd/html/adm/gpl.txt  # /home/httpd/html/adm/gpl.txt
 #  #
   
   
 # http://www.lon-capa.org/  # http://www.lon-capa.org/
 #  #
 # 5/26/99,6/4,6/10,6/11,6/14,6/15,6/26,6/28,6/30,  
 # 7/8,7/9,7/10,7/12,7/17,7/19,9/21,  
 # 10/7,10/8,10/9,10/11,10/13,10/15,11/4,11/16,  
 # 12/7,12/15,01/06,01/11,01/12,01/14,2/8,  
 # 03/07,05/31 Gerd Kortemeyer  
 # 06/29,06/30,07/14,07/15,07/17,07/20,07/25,09/18 Gerd Kortemeyer  
 # 12/05,12/13,12/29 Gerd Kortemeyer  
 # YEAR=2001  
 # 02/12 Gerd Kortemeyer  
 # 03/24 Gerd Kortemeyer  
 # 05/11,05/28,08/30 Gerd Kortemeyer  
 # 11/26,11/27 Gerd Kortemeyer  
 # 12/22 Gerd Kortemeyer  
 # YEAR=2002  
 # 01/20/02,02/05 Gerd Kortemeyer  
 # 02/05 Guy Albertelli  
 # 02/12 Gerd Kortemeyer  
 # 02/19 Matthew Hall  
 # 02/25 Gerd Kortemeyer  
 # 01/xx/2003 Ron Fox.. Remove preforking.  This makes the general daemon  
 #      logic simpler (and there were problems maintaining the preforked  
 #      population).  Since the time averaged connection rate is close to zero  
 #      because lonc's purpose is to maintain near continuous connnections,  
 #      preforking is not really needed.  
 # 08/xx/2003 Ron Fox:  Add management requests.  Management requests  
 #      will be validated via a call to ValidateManager. At present, this  
 #      is done by simple host verification.  In the future we can modify  
 #      this function to do a certificate check.  
 #      Management functions supported include:  
 #       - pushing /home/httpd/lonTabs/hosts.tab  
 #       - pushing /home/httpd/lonTabs/domain.tab  
 # 09/08/2003 Ron Fox:  Told lond to take care of change logging so we  
 #      don't have to remember it:  
 # $Log$  
 # Revision 1.153  2003/10/08 14:30:09  www  
 # Minor typos.  
 #  
 # Revision 1.152  2003/10/08 14:18:34  www  
 # Not good: this should be backported into 1.0.2!  
 #  
 # Revision 1.151  2003/10/03 15:11:03  albertel  
 # - if we fail to fetch an update to the file, don't blow away the old one  
 #   (this was the BUG that blew away that one default.sequence that Matthew  
 #    ended up restoring from data.)  
 #  
 # Revision 1.150  2003/09/30 10:16:06  foxr  
 # Added invocation of apachereload in ReloadApache sub.  
 # This completes the addtion of the reinit functionality.  
 #  
 # Revision 1.149  2003/09/30 09:44:13  foxr  
 # Tested UpdateHosts ability to  
 # - Remove live children for hosts that are no longer in the hosts.tab  
 # - Remove live children for hosts whose IPs have changed in the hosts.tab  
 #  
 # Revision 1.148  2003/09/29 10:09:18  foxr  
 # Put in logic to reinit lond itself (except for apache reload).  I don't believe  
 # this logic works correctly yet, however lond still does everything it used to doso I'll do the commit anyway.  
 #  
 # Revision 1.147  2003/09/23 11:23:31  foxr  
 # Comlplete implementation of reinit functionality.  Must still implement  
 # the actual initialization functionality, but the process can now  
 # receive the request and either invoke the appropriate internal function or  
 # signal the correct lonc.  
 #  
 # Revision 1.146  2003/09/16 10:28:14  foxr  
 # ReinitProcess - decode the process selector and produce the associated pid  
 # filename.  Note: While it is possible to test that valid process selectors are  
 # handled properly I am not able to test that invalid process selectors produce  
 # the appropriate error as lonManage also blocks the use of invalid process selectors.  
 #  
 # Revision 1.145  2003/09/16 10:13:20  foxr  
 # Added ReinitProcess function to oversee the parsing and processing of the  
 # reinit:<process> client request.  
 #  
 # Revision 1.144  2003/09/16 09:47:01  foxr  
 # Added skeletal support for SIGUSR2 (update hosts.tab)  
 #  
 # Revision 1.143  2003/09/15 10:03:52  foxr  
 # Completed and tested code for pushfile.  
 #  
 # Revision 1.142  2003/09/09 20:47:46  www  
 # Permanently store chatroom entries in chatroom.log  
 #  
 # Revision 1.141  2003/09/08 10:32:07  foxr  
 # Added PushFile sub This sub oversees the push of a new configuration table file  
 # Currently supported files are:  
 # - hosts.tab   (transaction pushfile:hosts:contents)  
 # - domain.tab  (transaction pushfile:domain:contents)  
 #  
   
   
 use strict;  use strict;
 use lib '/home/httpd/lib/perl/';  use lib '/home/httpd/lib/perl/';
Line 133  use Authen::Krb4; Line 45  use Authen::Krb4;
 use Authen::Krb5;  use Authen::Krb5;
 use lib '/home/httpd/lib/perl/';  use lib '/home/httpd/lib/perl/';
 use localauth;  use localauth;
   use localenroll;
 use File::Copy;  use File::Copy;
   use LONCAPA::ConfigFileEdit;
   use LONCAPA::lonlocal;
   use LONCAPA::lonssl;
   
 my $DEBUG = 0;       # Non zero to enable debug log entries.  my $DEBUG = 0;       # Non zero to enable debug log entries.
   
Line 146  my $currenthostid; Line 62  my $currenthostid;
 my $currentdomainid;  my $currentdomainid;
   
 my $client;  my $client;
 my $clientip;  my $clientip; # IP address of client.
   my $clientdns; # DNS name of client.
   my $clientname; # LonCAPA name of client.
   
 my $server;  my $server;
 my $thisserver;  my $thisserver; # DNS of us.
   
   my $keymode;
   
   my $cipher; # Cipher key negotiated with client
   my $tmpsnum = 0; # Id of tmpputs.
   
   # 
   #   Connection type is:
   #      client                   - All client actions are allowed
   #      manager                  - only management functions allowed.
   #      both                     - Both management and client actions are allowed
   #
   
   my $ConnectionType;
   
   my %hostid; # ID's for hosts in cluster by ip.
   my %hostdom; # LonCAPA domain for hosts in cluster.
   my %hostip; # IPs for hosts in cluster.
   my %hostdns; # ID's of hosts looked up by DNS name.
   
   my %managers; # Ip -> manager names
   
 my %hostid;  
 my %hostdom;  
 my %hostip;  
 my %perlvar; # Will have the apache conf defined perl vars.  my %perlvar; # Will have the apache conf defined perl vars.
   
 #  #
   #   The hash below is used for command dispatching, and is therefore keyed on the request keyword.
   #    Each element of the hash contains a reference to an array that contains:
   #          A reference to a sub that executes the request corresponding to the keyword.
   #          A flag that is true if the request must be encoded to be acceptable.
   #          A mask with bits as follows:
   #                      CLIENT_OK    - Set when the function is allowed by ordinary clients
   #                      MANAGER_OK   - Set when the function is allowed to manager clients.
   #
   my $CLIENT_OK  = 1;
   my $MANAGER_OK = 2;
   my %Dispatcher;
   
   
   #
 #  The array below are password error strings."  #  The array below are password error strings."
 #  #
 my $lastpwderror    = 13; # Largest error number from lcpasswd.  my $lastpwderror    = 13; # Largest error number from lcpasswd.
Line 194  my @adderrors    = ("ok", Line 144  my @adderrors    = ("ok",
     "lcuseradd Password mismatch");      "lcuseradd Password mismatch");
   
   
   
   #
   #   Statistics that are maintained and dislayed in the status line.
   #
   my $Transactions; # Number of attempted transactions.
   my $Failures; # Number of transcations failed.
   
   #   ResetStatistics: 
   #      Resets the statistics counters:
   #
   sub ResetStatistics {
       $Transactions = 0;
       $Failures     = 0;
   }
   
   
   
   #------------------------------------------------------------------------
   #
   #   LocalConnection
   #     Completes the formation of a locally authenticated connection.
   #     This function will ensure that the 'remote' client is really the
   #     local host.  If not, the connection is closed, and the function fails.
   #     If so, initcmd is parsed for the name of a file containing the
   #     IDEA session key.  The fie is opened, read, deleted and the session
   #     key returned to the caller.
   #
   # Parameters:
   #   $Socket      - Socket open on client.
   #   $initcmd     - The full text of the init command.
   #
   # Implicit inputs:
   #    $clientdns  - The DNS name of the remote client.
   #    $thisserver - Our DNS name.
   #
   # Returns:
   #     IDEA session key on success.
   #     undef on failure.
   #
   sub LocalConnection {
       my ($Socket, $initcmd) = @_;
       Debug("Attempting local connection: $initcmd client: $clientdns me: $thisserver");
       if($clientdns ne $thisserver) {
    &logthis('<font color="red"> LocalConnection rejecting non local: '
    ."$clientdns ne $thisserver </font>");
    close $Socket;
    return undef;
       } 
       else {
    chomp($initcmd); # Get rid of \n in filename.
    my ($init, $type, $name) = split(/:/, $initcmd);
    Debug(" Init command: $init $type $name ");
   
    # Require that $init = init, and $type = local:  Otherwise
    # the caller is insane:
   
    if(($init ne "init") && ($type ne "local")) {
       &logthis('<font color = "red"> LocalConnection: caller is insane! '
        ."init = $init, and type = $type </font>");
       close($Socket);;
       return undef;
   
    }
    #  Now get the key filename:
   
    my $IDEAKey = lonlocal::ReadKeyFile($name);
    return $IDEAKey;
       }
   }
   #------------------------------------------------------------------------------
   #
   #  SSLConnection
   #   Completes the formation of an ssh authenticated connection. The
   #   socket is promoted to an ssl socket.  If this promotion and the associated
   #   certificate exchange are successful, the IDEA key is generated and sent
   #   to the remote peer via the SSL tunnel. The IDEA key is also returned to
   #   the caller after the SSL tunnel is torn down.
   #
   # Parameters:
   #   Name              Type             Purpose
   #   $Socket          IO::Socket::INET  Plaintext socket.
   #
   # Returns:
   #    IDEA key on success.
   #    undef on failure.
   #
   sub SSLConnection {
       my $Socket   = shift;
   
       Debug("SSLConnection: ");
       my $KeyFile         = lonssl::KeyFile();
       if(!$KeyFile) {
    my $err = lonssl::LastError();
    &logthis("<font color=\"red\"> CRITICAL"
    ."Can't get key file $err </font>");
    return undef;
       }
       my ($CACertificate,
    $Certificate) = lonssl::CertificateFile();
   
   
       # If any of the key, certificate or certificate authority 
       # certificate filenames are not defined, this can't work.
   
       if((!$Certificate) || (!$CACertificate)) {
    my $err = lonssl::LastError();
    &logthis("<font color=\"red\"> CRITICAL"
    ."Can't get certificates: $err </font>");
   
    return undef;
       }
       Debug("Key: $KeyFile CA: $CACertificate Cert: $Certificate");
   
       # Indicate to our peer that we can procede with
       # a transition to ssl authentication:
   
       print $Socket "ok:ssl\n";
   
       Debug("Approving promotion -> ssl");
       #  And do so:
   
       my $SSLSocket = lonssl::PromoteServerSocket($Socket,
    $CACertificate,
    $Certificate,
    $KeyFile);
       if(! ($SSLSocket) ) { # SSL socket promotion failed.
    my $err = lonssl::LastError();
    &logthis("<font color=\"red\"> CRITICAL "
    ."SSL Socket promotion failed: $err </font>");
    return undef;
       }
       Debug("SSL Promotion successful");
   
       # 
       #  The only thing we'll use the socket for is to send the IDEA key
       #  to the peer:
   
       my $Key = lonlocal::CreateCipherKey();
       print $SSLSocket "$Key\n";
   
       lonssl::Close($SSLSocket); 
   
       Debug("Key exchange complete: $Key");
   
       return $Key;
   }
   #
   #     InsecureConnection: 
   #        If insecure connections are allowd,
   #        exchange a challenge with the client to 'validate' the
   #        client (not really, but that's the protocol):
   #        We produce a challenge string that's sent to the client.
   #        The client must then echo the challenge verbatim to us.
   #
   #  Parameter:
   #      Socket      - Socket open on the client.
   #  Returns:
   #      1           - success.
   #      0           - failure (e.g.mismatch or insecure not allowed).
   #
   sub InsecureConnection {
       my $Socket  =  shift;
   
       #   Don't even start if insecure connections are not allowed.
   
       if(! $perlvar{londAllowInsecure}) { # Insecure connections not allowed.
    return 0;
       }
   
       #   Fabricate a challenge string and send it..
   
       my $challenge = "$$".time; # pid + time.
       print $Socket "$challenge\n";
       &status("Waiting for challenge reply");
   
       my $answer = <$Socket>;
       $answer    =~s/\W//g;
       if($challenge eq $answer) {
    return 1;
       } 
       else {
    logthis("<font color='blue'>WARNING client did not respond to challenge</font>");
    &status("No challenge reqply");
    return 0;
       }
       
   
   }
   
 #  #
 #   GetCertificate: Given a transaction that requires a certificate,  #   GetCertificate: Given a transaction that requires a certificate,
 #   this function will extract the certificate from the transaction  #   this function will extract the certificate from the transaction
Line 211  sub GetCertificate { Line 350  sub GetCertificate {
     return $clientip;      return $clientip;
 }  }
   
   #
   #   Return true if client is a manager.
   #
   sub isManager {
       return (($ConnectionType eq "manager") || ($ConnectionType eq "both"));
   }
   #
   #   Return tru if client can do client functions
   #
   sub isClient {
       return (($ConnectionType eq "client") || ($ConnectionType eq "both"));
   }
   
   
   #
   #   ReadManagerTable: Reads in the current manager table. For now this is
   #                     done on each manager authentication because:
   #                     - These authentications are not frequent
   #                     - This allows dynamic changes to the manager table
   #                       without the need to signal to the lond.
   #
   
   sub ReadManagerTable {
   
       #   Clean out the old table first..
   
      foreach my $key (keys %managers) {
         delete $managers{$key};
      }
   
      my $tablename = $perlvar{'lonTabDir'}."/managers.tab";
      if (!open (MANAGERS, $tablename)) {
         logthis('<font color="red">No manager table.  Nobody can manage!!</font>');
         return;
      }
      while(my $host = <MANAGERS>) {
         chomp($host);
         if ($host =~ "^#") {                  # Comment line.
            next;
         }
         if (!defined $hostip{$host}) { # This is a non cluster member
       #  The entry is of the form:
       #    cluname:hostname
       #  cluname - A 'cluster hostname' is needed in order to negotiate
       #            the host key.
       #  hostname- The dns name of the host.
       #
             my($cluname, $dnsname) = split(/:/, $host);
             
             my $ip = gethostbyname($dnsname);
             if(defined($ip)) {                 # bad names don't deserve entry.
               my $hostip = inet_ntoa($ip);
               $managers{$hostip} = $cluname;
               logthis('<font color="green"> registering manager '.
                       "$dnsname as $cluname with $hostip </font>\n");
            }
         } else {
            logthis('<font color="green"> existing host'." $host</font>\n");
            $managers{$hostip{$host}} = $host;  # Use info from cluster tab if clumemeber
         }
      }
   }
   
 #  #
 #  ValidManager: Determines if a given certificate represents a valid manager.  #  ValidManager: Determines if a given certificate represents a valid manager.
Line 222  sub GetCertificate { Line 423  sub GetCertificate {
 sub ValidManager {  sub ValidManager {
     my $certificate = shift;       my $certificate = shift; 
   
     my $hostentry   = $hostid{$certificate};      return isManager;
     if ($hostentry ne undef) {  
  &logthis('<font color="yellow">Authenticating manager'.  
  " $hostentry</font>");  
  return 1;  
     } else {  
  &logthis('<font color="red"> Failed manager authentication '.  
  "$certificate </font>");  
     }  
 }  }
 #  #
 #  CopyFile:  Called as part of the process of installing a   #  CopyFile:  Called as part of the process of installing a 
Line 244  sub ValidManager { Line 437  sub ValidManager {
 #     1   - Success.  #     1   - Success.
 #  #
 sub CopyFile {  sub CopyFile {
     my $oldfile = shift;  
     my $newfile = shift;      my ($oldfile, $newfile) = @_;
   
     #  The file must exist:      #  The file must exist:
   
Line 281  sub CopyFile { Line 474  sub CopyFile {
  return 0;   return 0;
     }      }
 }  }
   #
   #  Host files are passed out with externally visible host IPs.
   #  If, for example, we are behind a fire-wall or NAT host, our 
   #  internally visible IP may be different than the externally
   #  visible IP.  Therefore, we always adjust the contents of the
   #  host file so that the entry for ME is the IP that we believe
   #  we have.  At present, this is defined as the entry that
   #  DNS has for us.  If by some chance we are not able to get a
   #  DNS translation for us, then we assume that the host.tab file
   #  is correct.  
   #    BUGBUGBUG - in the future, we really should see if we can
   #       easily query the interface(s) instead.
   # Parameter(s):
   #     contents    - The contents of the host.tab to check.
   # Returns:
   #     newcontents - The adjusted contents.
   #
   #
   sub AdjustHostContents {
       my $contents  = shift;
       my $adjusted;
       my $me        = $perlvar{'lonHostID'};
   
    foreach my $line (split(/\n/,$contents)) {
    if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/))) {
       chomp($line);
       my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon)=split(/:/,$line);
       if ($id eq $me) {
             my $ip = gethostbyname($name);
             my $ipnew = inet_ntoa($ip);
            $ip = $ipnew;
    #  Reconstruct the host line and append to adjusted:
   
      my $newline = "$id:$domain:$role:$name:$ip";
      if($maxcon ne "") { # Not all hosts have loncnew tuning params
        $newline .= ":$maxcon:$idleto:$mincon";
      }
      $adjusted .= $newline."\n";
   
         } else { # Not me, pass unmodified.
      $adjusted .= $line."\n";
         }
    } else {                  # Blank or comment never re-written.
       $adjusted .= $line."\n"; # Pass blanks and comments as is.
    }
    }
    return $adjusted;
   }
 #  #
 #   InstallFile: Called to install an administrative file:  #   InstallFile: Called to install an administrative file:
 #       - The file is created with <name>.tmp  #       - The file is created with <name>.tmp
Line 298  sub CopyFile { Line 538  sub CopyFile {
 #      0       - failure and $! has an errno.  #      0       - failure and $! has an errno.
 #  #
 sub InstallFile {  sub InstallFile {
     my $Filename = shift;  
     my $Contents = shift;      my ($Filename, $Contents) = @_;
     my $TempFile = $Filename.".tmp";      my $TempFile = $Filename.".tmp";
   
     #  Open the file for write:      #  Open the file for write:
Line 323  sub InstallFile { Line 563  sub InstallFile {
     return 1;      return 1;
 }  }
   
   
   #
   #   ConfigFileFromSelector: converts a configuration file selector
   #                 (one of host or domain at this point) into a 
   #                 configuration file pathname.
   #
   #  Parameters:
   #      selector  - Configuration file selector.
   #  Returns:
   #      Full path to the file or undef if the selector is invalid.
   #
   sub ConfigFileFromSelector {
       my $selector   = shift;
       my $tablefile;
   
       my $tabledir = $perlvar{'lonTabDir'}.'/';
       if ($selector eq "hosts") {
    $tablefile = $tabledir."hosts.tab";
       } elsif ($selector eq "domain") {
    $tablefile = $tabledir."domain.tab";
       } else {
    return undef;
       }
       return $tablefile;
   
   }
 #  #
 #   PushFile:  Called to do an administrative push of a file.  #   PushFile:  Called to do an administrative push of a file.
 #              - Ensure the file being pushed is one we support.  #              - Ensure the file being pushed is one we support.
Line 352  sub PushFile { Line 618  sub PushFile {
     # part of some elaborate spoof that managed somehow to authenticate.      # part of some elaborate spoof that managed somehow to authenticate.
     #      #
   
     my $tablefile = $perlvar{'lonTabDir'}.'/'; # need to precede with dir.  
     if ($filename eq "host") {      my $tablefile = ConfigFileFromSelector($filename);
  $tablefile .= "hosts.tab";      if(! (defined $tablefile)) {
     } elsif ($filename eq "domain") {  
  $tablefile .= "domain.tab";  
     } else {  
  return "refused";   return "refused";
     }      }
     #      #
Line 374  sub PushFile { Line 637  sub PushFile {
     &logthis('<font color="green"> Pushfile: backed up '      &logthis('<font color="green"> Pushfile: backed up '
     .$tablefile." to $backupfile</font>");      .$tablefile." to $backupfile</font>");
           
       #  If the file being pushed is the host file, we adjust the entry for ourself so that the
       #  IP will be our current IP as looked up in dns.  Note this is only 99% good as it's possible
       #  to conceive of conditions where we don't have a DNS entry locally.  This is possible in a 
       #  network sense but it doesn't make much sense in a LonCAPA sense so we ignore (for now)
       #  that possibilty.
   
       if($filename eq "host") {
    $contents = AdjustHostContents($contents);
       }
   
     #  Install the new file:      #  Install the new file:
   
     if(!InstallFile($tablefile, $contents)) {      if(!InstallFile($tablefile, $contents)) {
Line 439  sub ReinitProcess { Line 712  sub ReinitProcess {
     }      }
     return 'ok';      return 'ok';
 }  }
   #   Validate a line in a configuration file edit script:
   #   Validation includes:
   #     - Ensuring the command is valid.
   #     - Ensuring the command has sufficient parameters
   #   Parameters:
   #     scriptline - A line to validate (\n has been stripped for what it's worth).
   #
   #   Return:
   #      0     - Invalid scriptline.
   #      1     - Valid scriptline
   #  NOTE:
   #     Only the command syntax is checked, not the executability of the
   #     command.
   #
   sub isValidEditCommand {
       my $scriptline = shift;
   
       #   Line elements are pipe separated:
   
       my ($command, $key, $newline)  = split(/\|/, $scriptline);
       &logthis('<font color="green"> isValideditCommand checking: '.
        "Command = '$command', Key = '$key', Newline = '$newline' </font>\n");
       
       if ($command eq "delete") {
    #
    #   key with no newline.
    #
    if( ($key eq "") || ($newline ne "")) {
       return 0; # Must have key but no newline.
    } else {
       return 1; # Valid syntax.
    }
       } elsif ($command eq "replace") {
    #
    #   key and newline:
    #
    if (($key eq "") || ($newline eq "")) {
       return 0;
    } else {
       return 1;
    }
       } elsif ($command eq "append") {
    if (($key ne "") && ($newline eq "")) {
       return 1;
    } else {
       return 0;
    }
       } else {
    return 0; # Invalid command.
       }
       return 0; # Should not get here!!!
   }
   #
   #   ApplyEdit - Applies an edit command to a line in a configuration 
   #               file.  It is the caller's responsiblity to validate the
   #               edit line.
   #   Parameters:
   #      $directive - A single edit directive to apply.  
   #                   Edit directives are of the form:
   #                  append|newline      - Appends a new line to the file.
   #                  replace|key|newline - Replaces the line with key value 'key'
   #                  delete|key          - Deletes the line with key value 'key'.
   #      $editor   - A config file editor object that contains the
   #                  file being edited.
   #
   sub ApplyEdit {
   
       my ($directive, $editor) = @_;
   
       # Break the directive down into its command and its parameters
       # (at most two at this point.  The meaning of the parameters, if in fact
       #  they exist depends on the command).
   
       my ($command, $p1, $p2) = split(/\|/, $directive);
   
       if($command eq "append") {
    $editor->Append($p1);          # p1 - key p2 null.
       } elsif ($command eq "replace") {
    $editor->ReplaceLine($p1, $p2);   # p1 - key p2 = newline.
       } elsif ($command eq "delete") {
    $editor->DeleteLine($p1);         # p1 - key p2 null.
       } else {          # Should not get here!!!
    die "Invalid command given to ApplyEdit $command"
       }
   }
   #
   # AdjustOurHost:
   #           Adjusts a host file stored in a configuration file editor object
   #           for the true IP address of this host. This is necessary for hosts
   #           that live behind a firewall.
   #           Those hosts have a publicly distributed IP of the firewall, but
   #           internally must use their actual IP.  We assume that a given
   #           host only has a single IP interface for now.
   # Formal Parameters:
   #     editor   - The configuration file editor to adjust.  This
   #                editor is assumed to contain a hosts.tab file.
   # Strategy:
   #    - Figure out our hostname.
   #    - Lookup the entry for this host.
   #    - Modify the line to contain our IP
   #    - Do a replace for this host.
   sub AdjustOurHost {
       my $editor        = shift;
   
       # figure out who I am.
   
       my $myHostName    = $perlvar{'lonHostID'}; # LonCAPA hostname.
   
       #  Get my host file entry.
   
       my $ConfigLine    = $editor->Find($myHostName);
       if(! (defined $ConfigLine)) {
    die "AdjustOurHost - no entry for me in hosts file $myHostName";
       }
       # figure out my IP:
       #   Use the config line to get my hostname.
       #   Use gethostbyname to translate that into an IP address.
       #
       my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon) = split(/:/,$ConfigLine);
       my $BinaryIp = gethostbyname($name);
       my $ip       = inet_ntoa($ip);
       #
       #  Reassemble the config line from the elements in the list.
       #  Note that if the loncnew items were not present before, they will
       #  be now even if they would be empty
       #
       my $newConfigLine = $id;
       foreach my $item ($domain, $role, $name, $ip, $maxcon, $idleto, $mincon) {
    $newConfigLine .= ":".$item;
       }
       #  Replace the line:
   
       $editor->ReplaceLine($id, $newConfigLine);
       
   }
   #
   #   ReplaceConfigFile:
   #              Replaces a configuration file with the contents of a
   #              configuration file editor object.
   #              This is done by:
   #              - Copying the target file to <filename>.old
   #              - Writing the new file to <filename>.tmp
   #              - Moving <filename.tmp>  -> <filename>
   #              This laborious process ensures that the system is never without
   #              a configuration file that's at least valid (even if the contents
   #              may be dated).
   #   Parameters:
   #        filename   - Name of the file to modify... this is a full path.
   #        editor     - Editor containing the file.
   #
   sub ReplaceConfigFile {
       
       my ($filename, $editor) = @_;
   
       CopyFile ($filename, $filename.".old");
   
       my $contents  = $editor->Get(); # Get the contents of the file.
   
       InstallFile($filename, $contents);
   }
   #   
   #
   #   Called to edit a configuration table  file
   #   Parameters:
   #      request           - The entire command/request sent by lonc or lonManage
   #   Return:
   #      The reply to send to the client.
   #
   sub EditFile {
       my $request = shift;
   
       #  Split the command into it's pieces:  edit:filetype:script
   
       my ($request, $filetype, $script) = split(/:/, $request,3); # : in script
   
       #  Check the pre-coditions for success:
   
       if($request != "edit") { # Something is amiss afoot alack.
    return "error:edit request detected, but request != 'edit'\n";
       }
       if( ($filetype ne "hosts")  &&
    ($filetype ne "domain")) {
    return "error:edit requested with invalid file specifier: $filetype \n";
       }
   
       #   Split the edit script and check it's validity.
   
       my @scriptlines = split(/\n/, $script);  # one line per element.
       my $linecount   = scalar(@scriptlines);
       for(my $i = 0; $i < $linecount; $i++) {
    chomp($scriptlines[$i]);
    if(!isValidEditCommand($scriptlines[$i])) {
       return "error:edit with bad script line: '$scriptlines[$i]' \n";
    }
       }
   
       #   Execute the edit operation.
       #   - Create a config file editor for the appropriate file and 
       #   - execute each command in the script:
       #
       my $configfile = ConfigFileFromSelector($filetype);
       if (!(defined $configfile)) {
    return "refused\n";
       }
       my $editor = ConfigFileEdit->new($configfile);
   
       for (my $i = 0; $i < $linecount; $i++) {
    ApplyEdit($scriptlines[$i], $editor);
       }
       # If the file is the host file, ensure that our host is
       # adjusted to have our ip:
       #
       if($filetype eq "host") {
    AdjustOurHost($editor);
       }
       #  Finally replace the current file with our file.
       #
       ReplaceConfigFile($configfile, $editor);
   
       return "ok\n";
   }
   
   #---------------------------------------------------------------
   #
   # Manipulation of hash based databases (factoring out common code
   # for later use as we refactor.
   #
   #  Ties a domain level resource file to a hash.
   #  If requested a history entry is created in the associated hist file.
   #
   #  Parameters:
   #     domain    - Name of the domain in which the resource file lives.
   #     namespace - Name of the hash within that domain.
   #     how       - How to tie the hash (e.g. GDBM_WRCREAT()).
   #     loghead   - Optional parameter, if present a log entry is created
   #                 in the associated history file and this is the first part
   #                  of that entry.
   #     logtail   - Goes along with loghead,  The actual logentry is of the
   #                 form $loghead:<timestamp>:logtail.
   # Returns:
   #    Reference to a hash bound to the db file or alternatively undef
   #    if the tie failed.
   #
   sub tie_domain_hash {
       my ($domain,$namespace,$how,$loghead,$logtail) = @_;
       
       # Filter out any whitespace in the domain name:
       
       $domain =~ s/\W//g;
       
       # We have enough to go on to tie the hash:
       
       my $user_top_dir   = $perlvar{'lonUsersDir'};
       my $domain_dir     = $user_top_dir."/$domain";
       my $resource_file  = $domain_dir."/$namespace.db";
       my %hash;
       if(tie(%hash, 'GDBM_File', $resource_file, $how, 0640)) {
    if (defined($loghead)) { # Need to log the operation.
       my $logFh = IO::File->new(">>$domain_dir/$namespace.hist");
       if($logFh) {
    my $timestamp = time;
    print $logFh "$loghead:$timestamp:$logtail\n";
       }
       $logFh->close;
    }
    return \%hash; # Return the tied hash.
       } else {
    return undef; # Tie failed.
       }
   }
   
   #
   #   Ties a user's resource file to a hash.  
   #   If necessary, an appropriate history
   #   log file entry is made as well.
   #   This sub factors out common code from the subs that manipulate
   #   the various gdbm files that keep keyword value pairs.
   # Parameters:
   #   domain       - Name of the domain the user is in.
   #   user         - Name of the 'current user'.
   #   namespace    - Namespace representing the file to tie.
   #   how          - What the tie is done to (e.g. GDBM_WRCREAT().
   #   loghead      - Optional first part of log entry if there may be a
   #                  history file.
   #   what         - Optional tail of log entry if there may be a history
   #                  file.
   # Returns:
   #   hash to which the database is tied.  It's up to the caller to untie.
   #   undef if the has could not be tied.
   #
   sub tie_user_hash {
       my ($domain,$user,$namespace,$how,$loghead,$what) = @_;
   
       $namespace=~s/\//\_/g; # / -> _
       $namespace=~s/\W//g; # whitespace eliminated.
       my $proname     = propath($domain, $user);
      
       #  Tie the database.
       
       my %hash;
       if(tie(%hash, 'GDBM_File', "$proname/$namespace.db",
      $how, 0640)) {
    # If this is a namespace for which a history is kept,
    # make the history log entry:    
    if (($namespace =~/^nohist\_/) && (defined($loghead))) {
       my $args = scalar @_;
       Debug(" Opening history: $namespace $args");
       my $hfh = IO::File->new(">>$proname/$namespace.hist"); 
       if($hfh) {
    my $now = time;
    print $hfh "$loghead:$now:$what\n";
       }
       $hfh->close;
    }
    return \%hash;
       } else {
    return undef;
       }
       
   }
   #---------------------------------------------------------------
   #
   #   Getting, decoding and dispatching requests:
   #
   
   #
   #   Get a Request:
   #   Gets a Request message from the client.  The transaction
   #   is defined as a 'line' of text.  We remove the new line
   #   from the text line.  
   #   
   sub get_request {
       my $input = <$client>;
       chomp($input);
   
       Debug("Request = $input\n");
   
       &status('Processing '.$clientname.':'.$input);
   
       return $input;
   }
   #
   #   Decipher encoded traffic
   #  Parameters:
   #     input      - Encoded data.
   #  Returns:
   #     Decoded data or undef if encryption key was not yet negotiated.
   #  Implicit input:
   #     cipher  - This global holds the negotiated encryption key.
   #
   sub decipher {
       my ($input)  = @_;
       my $output = '';
      
      
       if($cipher) {
    my($enc, $enclength, $encinput) = split(/:/, $input);
    for(my $encidx = 0; $encidx < length($encinput); $encidx += 16) {
       $output .= 
    $cipher->decrypt(pack("H16", substr($encinput, $encidx, 16)));
    }
    return substr($output, 0, $enclength);
       } else {
    return undef;
       }
   }
   
   #
   #   Register a command processor.  This function is invoked to register a sub
   #   to process a request.  Once registered, the ProcessRequest sub can automatically
   #   dispatch requests to an appropriate sub, and do the top level validity checking
   #   as well:
   #    - Is the keyword recognized.
   #    - Is the proper client type attempting the request.
   #    - Is the request encrypted if it has to be.
   #   Parameters:
   #    $request_name         - Name of the request being registered.
   #                           This is the command request that will match
   #                           against the hash keywords to lookup the information
   #                           associated with the dispatch information.
   #    $procedure           - Reference to a sub to call to process the request.
   #                           All subs get called as follows:
   #                             Procedure($cmd, $tail, $replyfd, $key)
   #                             $cmd    - the actual keyword that invoked us.
   #                             $tail   - the tail of the request that invoked us.
   #                             $replyfd- File descriptor connected to the client
   #    $must_encode          - True if the request must be encoded to be good.
   #    $client_ok            - True if it's ok for a client to request this.
   #    $manager_ok           - True if it's ok for a manager to request this.
   # Side effects:
   #      - On success, the Dispatcher hash has an entry added for the key $RequestName
   #      - On failure, the program will die as it's a bad internal bug to try to 
   #        register a duplicate command handler.
   #
   sub register_handler {
       my ($request_name,
    $procedure,
    $must_encode,
    $client_ok,
    $manager_ok)   = @_;
   
       #  Don't allow duplication#
      
       if (defined $Dispatcher{$request_name}) {
    die "Attempting to define a duplicate request handler for $request_name\n";
       }
       #   Build the client type mask:
       
       my $client_type_mask = 0;
       if($client_ok) {
    $client_type_mask  |= $CLIENT_OK;
       }
       if($manager_ok) {
    $client_type_mask  |= $MANAGER_OK;
       }
      
       #  Enter the hash:
         
       my @entry = ($procedure, $must_encode, $client_type_mask);
      
       $Dispatcher{$request_name} = \@entry;
      
      
   }
   
   
   #------------------------------------------------------------------
   
   
   
   
 #  #
 #  Convert an error return code from lcpasswd to a string value.  #  Convert an error return code from lcpasswd to a string value.
Line 469  sub catchexception { Line 1172  sub catchexception {
     my ($error)=@_;      my ($error)=@_;
     $SIG{'QUIT'}='DEFAULT';      $SIG{'QUIT'}='DEFAULT';
     $SIG{__DIE__}='DEFAULT';      $SIG{__DIE__}='DEFAULT';
     &logthis("<font color=red>CRITICAL: "      &status("Catching exception");
       &logthis("<font color='red'>CRITICAL: "
      ."ABNORMAL EXIT. Child $$ for server $thisserver died through "       ."ABNORMAL EXIT. Child $$ for server $thisserver died through "
      ."a crash with this error msg->[$error]</font>");       ."a crash with this error msg->[$error]</font>");
     &logthis('Famous last words: '.$status.' - '.$lastlog);      &logthis('Famous last words: '.$status.' - '.$lastlog);
Line 479  sub catchexception { Line 1183  sub catchexception {
 }  }
   
 sub timeout {  sub timeout {
     &logthis("<font color=ref>CRITICAL: TIME OUT ".$$."</font>");      &status("Handling Timeout");
       &logthis("<font color='red'>CRITICAL: TIME OUT ".$$."</font>");
     &catchexception('Timeout');      &catchexception('Timeout');
 }  }
 # -------------------------------- Set signal handlers to record abnormal exits  # -------------------------------- Set signal handlers to record abnormal exits
Line 531  $server = IO::Socket::INET->new(LocalPor Line 1236  $server = IO::Socket::INET->new(LocalPor
 # global variables  # global variables
   
 my %children               = ();       # keys are current child process IDs  my %children               = ();       # keys are current child process IDs
 my $children               = 0;        # current number of children  
   
 sub REAPER {                        # takes care of dead children  sub REAPER {                        # takes care of dead children
     $SIG{CHLD} = \&REAPER;      $SIG{CHLD} = \&REAPER;
     my $pid = wait;      &status("Handling child death");
     if (defined($children{$pid})) {      my $pid;
  &logthis("Child $pid died");      do {
  $children --;   $pid = waitpid(-1,&WNOHANG());
  delete $children{$pid};   if (defined($children{$pid})) {
     } else {      &logthis("Child $pid died");
  &logthis("Unknown Child $pid died");      delete($children{$pid});
    } elsif ($pid > 0) {
       &logthis("Unknown Child $pid died");
    }
       } while ( $pid > 0 );
       foreach my $child (keys(%children)) {
    $pid = waitpid($child,&WNOHANG());
    if ($pid > 0) {
       &logthis("Child $child - $pid looks like we missed it's death");
       delete($children{$pid});
    }
     }      }
       &status("Finished Handling child death");
 }  }
   
 sub HUNTSMAN {                      # signal handler for SIGINT  sub HUNTSMAN {                      # signal handler for SIGINT
       &status("Killing children (INT)");
     local($SIG{CHLD}) = 'IGNORE';   # we're going to kill our children      local($SIG{CHLD}) = 'IGNORE';   # we're going to kill our children
     kill 'INT' => keys %children;      kill 'INT' => keys %children;
     &logthis("Free socket: ".shutdown($server,2)); # free up socket      &logthis("Free socket: ".shutdown($server,2)); # free up socket
     my $execdir=$perlvar{'lonDaemons'};      my $execdir=$perlvar{'lonDaemons'};
     unlink("$execdir/logs/lond.pid");      unlink("$execdir/logs/lond.pid");
     &logthis("<font color=red>CRITICAL: Shutting down</font>");      &logthis("<font color='red'>CRITICAL: Shutting down</font>");
       &status("Done killing children");
     exit;                           # clean up with dignity      exit;                           # clean up with dignity
 }  }
   
 sub HUPSMAN {                      # signal handler for SIGHUP  sub HUPSMAN {                      # signal handler for SIGHUP
     local($SIG{CHLD}) = 'IGNORE';  # we're going to kill our children      local($SIG{CHLD}) = 'IGNORE';  # we're going to kill our children
       &status("Killing children for restart (HUP)");
     kill 'INT' => keys %children;      kill 'INT' => keys %children;
     &logthis("Free socket: ".shutdown($server,2)); # free up socket      &logthis("Free socket: ".shutdown($server,2)); # free up socket
     &logthis("<font color=red>CRITICAL: Restarting</font>");      &logthis("<font color='red'>CRITICAL: Restarting</font>");
     my $execdir=$perlvar{'lonDaemons'};      my $execdir=$perlvar{'lonDaemons'};
     unlink("$execdir/logs/lond.pid");      unlink("$execdir/logs/lond.pid");
       &status("Restarting self (HUP)");
     exec("$execdir/lond");         # here we go again      exec("$execdir/lond");         # here we go again
 }  }
   
 #  #
 #    Kill off hashes that describe the host table prior to re-reading it.  #    Kill off hashes that describe the host table prior to re-reading it.
 #    Hashes affected are:  #    Hashes affected are:
 #       %hostid, %hostdom %hostip  #       %hostid, %hostdom %hostip %hostdns.
 #  #
 sub KillHostHashes {  sub KillHostHashes {
     foreach my $key (keys %hostid) {      foreach my $key (keys %hostid) {
Line 580  sub KillHostHashes { Line 1299  sub KillHostHashes {
     foreach my $key (keys %hostip) {      foreach my $key (keys %hostip) {
  delete $hostip{$key};   delete $hostip{$key};
     }      }
       foreach my $key (keys %hostdns) {
    delete $hostdns{$key};
       }
 }  }
 #  #
 #   Read in the host table from file and distribute it into the various hashes:  #   Read in the host table from file and distribute it into the various hashes:
Line 590  sub KillHostHashes { Line 1312  sub KillHostHashes {
 sub ReadHostTable {  sub ReadHostTable {
   
     open (CONFIG,"$perlvar{'lonTabDir'}/hosts.tab") || die "Can't read host file";      open (CONFIG,"$perlvar{'lonTabDir'}/hosts.tab") || die "Can't read host file";
           my $myloncapaname = $perlvar{'lonHostID'};
       Debug("My loncapa name is : $myloncapaname");
     while (my $configline=<CONFIG>) {      while (my $configline=<CONFIG>) {
  my ($id,$domain,$role,$name,$ip)=split(/:/,$configline);   if (!($configline =~ /^\s*\#/)) {
  chomp($ip); $ip=~s/\D+$//;      my ($id,$domain,$role,$name,$ip)=split(/:/,$configline);
  $hostid{$ip}=$id;      chomp($ip); $ip=~s/\D+$//;
  $hostdom{$id}=$domain;      $hostid{$ip}=$id;         # LonCAPA name of host by IP.
  $hostip{$id}=$ip;      $hostdom{$id}=$domain;    # LonCAPA domain name of host. 
  if ($id eq $perlvar{'lonHostID'}) { $thisserver=$name; }      $hostip{$id}=$ip;      # IP address of host.
       $hostdns{$name} = $id;    # LonCAPA name of host by DNS.
   
       if ($id eq $perlvar{'lonHostID'}) { 
    Debug("Found me in the host table: $name");
    $thisserver=$name; 
       }
    }
     }      }
     close(CONFIG);      close(CONFIG);
 }  }
Line 623  sub ReloadApache { Line 1353  sub ReloadApache {
 #     now be honored.  #     now be honored.
 #  #
 sub UpdateHosts {  sub UpdateHosts {
       &status("Reload hosts.tab");
     logthis('<font color="blue"> Updating connections </font>');      logthis('<font color="blue"> Updating connections </font>');
     #      #
     #  The %children hash has the set of IP's we currently have children      #  The %children hash has the set of IP's we currently have children
Line 647  sub UpdateHosts { Line 1378  sub UpdateHosts {
  }   }
     }      }
     ReloadApache;      ReloadApache;
       &status("Finished reloading hosts.tab");
 }  }
   
   
 sub checkchildren {  sub checkchildren {
       &status("Checking on the children (sending signals)");
     &initnewstatus();      &initnewstatus();
     &logstatus();      &logstatus();
     &logthis('Going to check on the children');      &logthis('Going to check on the children');
Line 665  sub checkchildren { Line 1398  sub checkchildren {
     sleep 5;      sleep 5;
     $SIG{ALRM} = sub { die "timeout" };      $SIG{ALRM} = sub { die "timeout" };
     $SIG{__DIE__} = 'DEFAULT';      $SIG{__DIE__} = 'DEFAULT';
       &status("Checking on the children (waiting for reports)");
     foreach (sort keys %children) {      foreach (sort keys %children) {
         unless (-e "$docdir/lon-status/londchld/$_.txt") {          unless (-e "$docdir/lon-status/londchld/$_.txt") {
           eval {            eval {
Line 681  sub checkchildren { Line 1415  sub checkchildren {
         }          }
     }      }
     $SIG{ALRM} = 'DEFAULT';      $SIG{ALRM} = 'DEFAULT';
     $SIG{__DIE__} = \&catchcexception;      $SIG{__DIE__} = \&catchexception;
       &status("Finished checking children");
 }  }
   
 # --------------------------------------------------------------------- Logging  # --------------------------------------------------------------------- Logging
Line 703  sub Debug { Line 1438  sub Debug {
  &logthis($message);   &logthis($message);
     }      }
 }  }
   
   #
   #   Sub to do replies to client.. this gives a hook for some
   #   debug tracing too:
   #  Parameters:
   #     fd      - File open on client.
   #     reply   - Text to send to client.
   #     request - Original request from client.
   #
   sub Reply {
   
       my ($fd, $reply, $request) = @_;
   
       print $fd $reply;
       Debug("Request was $request  Reply was $reply");
   
   }
 # ------------------------------------------------------------------ Log status  # ------------------------------------------------------------------ Log status
   
 sub logstatus {  sub logstatus {
       &status("Doing logging");
     my $docdir=$perlvar{'lonDocRoot'};      my $docdir=$perlvar{'lonDocRoot'};
     {      {
     my $fh=IO::File->new(">>$docdir/lon-status/londstatus.txt");      my $fh=IO::File->new(">>$docdir/lon-status/londstatus.txt");
     print $fh $$."\t".$currenthostid."\t".$status."\t".$lastlog."\n";      print $fh $$."\t".$clientname."\t".$currenthostid."\t"
    .$status."\t".$lastlog."\t $keymode\n";
     $fh->close();      $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;          print $fh $status."\n".$lastlog."\n".time."\n$keymode";
         $fh->close();          $fh->close();
     }      }
       &status("Finished logging");
 }  }
   
 sub initnewstatus {  sub initnewstatus {
Line 772  sub reconlonc { Line 1528  sub reconlonc {
             kill USR1 => $loncpid;              kill USR1 => $loncpid;
         } else {          } else {
     &logthis(      &logthis(
               "<font color=red>CRITICAL: "                "<font color='red'>CRITICAL: "
              ."lonc at pid $loncpid not responding, giving up</font>");               ."lonc at pid $loncpid not responding, giving up</font>");
         }          }
     } else {      } else {
       &logthis('<font color=red>CRITICAL: lonc not running, giving up</font>');        &logthis('<font color="red">CRITICAL: lonc not running, giving up</font>');
     }      }
 }  }
   
Line 880  my $execdir=$perlvar{'lonDaemons'}; Line 1636  my $execdir=$perlvar{'lonDaemons'};
 open (PIDSAVE,">$execdir/logs/lond.pid");  open (PIDSAVE,">$execdir/logs/lond.pid");
 print PIDSAVE "$$\n";  print PIDSAVE "$$\n";
 close(PIDSAVE);  close(PIDSAVE);
 &logthis("<font color=red>CRITICAL: ---------- Starting ----------</font>");  &logthis("<font color='red'>CRITICAL: ---------- Starting ----------</font>");
 &status('Starting');  &status('Starting');
   
   
Line 904  ReadHostTable; Line 1660  ReadHostTable;
 #   along the connection.  #   along the connection.
   
 while (1) {  while (1) {
       &status('Starting accept');
     $client = $server->accept() or next;      $client = $server->accept() or next;
       &status('Accepted '.$client.' off to spawn');
     make_new_child($client);      make_new_child($client);
       &status('Finished spawning');
 }  }
   
 sub make_new_child {  sub make_new_child {
     my $pid;      my $pid;
     my $cipher;  #    my $cipher;     # Now global
     my $sigset;      my $sigset;
   
     $client = shift;      $client = shift;
     &logthis("Attempting to start child");          &status('Starting new child '.$client);
       &logthis('<font color="green"> Attempting to start child ('.$client.
        ")</font>");    
     # block signal for fork      # block signal for fork
     $sigset = POSIX::SigSet->new(SIGINT);      $sigset = POSIX::SigSet->new(SIGINT);
     sigprocmask(SIG_BLOCK, $sigset)      sigprocmask(SIG_BLOCK, $sigset)
Line 930  sub make_new_child { Line 1691  sub make_new_child {
     #  the pid hash.      #  the pid hash.
     #      #
     my $caller = getpeername($client);      my $caller = getpeername($client);
     my ($port,$iaddr)=unpack_sockaddr_in($caller);      my ($port,$iaddr);
     $clientip=inet_ntoa($iaddr);      if (defined($caller) && length($caller) > 0) {
    ($port,$iaddr)=unpack_sockaddr_in($caller);
       } else {
    &logthis("Unable to determine who caller was, getpeername returned nothing");
       }
       if (defined($iaddr)) {
    $clientip  = inet_ntoa($iaddr);
    Debug("Connected with $clientip");
    $clientdns = gethostbyaddr($iaddr, AF_INET);
    Debug("Connected with $clientdns by name");
       } else {
    &logthis("Unable to determine clientip");
    $clientip='Unavailable';
       }
           
     if ($pid) {      if ($pid) {
         # Parent records the child's birth and returns.          # Parent records the child's birth and returns.
         sigprocmask(SIG_UNBLOCK, $sigset)          sigprocmask(SIG_UNBLOCK, $sigset)
             or die "Can't unblock SIGINT for fork: $!\n";              or die "Can't unblock SIGINT for fork: $!\n";
         $children{$pid} = $clientip;          $children{$pid} = $clientip;
         $children++;  
         &status('Started child '.$pid);          &status('Started child '.$pid);
         return;          return;
     } else {      } else {
Line 955  sub make_new_child { Line 1728  sub make_new_child {
         sigprocmask(SIG_UNBLOCK, $sigset)          sigprocmask(SIG_UNBLOCK, $sigset)
             or die "Can't unblock SIGINT for fork: $!\n";              or die "Can't unblock SIGINT for fork: $!\n";
   
         my $tmpsnum=0;  #        my $tmpsnum=0;            # Now global
 #---------------------------------------------------- kerberos 5 initialization  #---------------------------------------------------- kerberos 5 initialization
         &Authen::Krb5::init_context();          &Authen::Krb5::init_context();
         &Authen::Krb5::init_ets();          &Authen::Krb5::init_ets();
   
             &status('Accepted connection');   &status('Accepted connection');
 # =============================================================================  # =============================================================================
             # do something with the connection              # do something with the connection
 # -----------------------------------------------------------------------------  # -----------------------------------------------------------------------------
  # see if we know client and check for spoof IP by challenge   # see if we know client and 'check' for spoof IP by ineffective challenge
   
             my $clientrec=($hostid{$clientip} ne undef);   ReadManagerTable; # May also be a manager!!
             &logthis(  
 "<font color=yellow>INFO: Connection, $clientip ($hostid{$clientip})</font>"   my $clientrec=($hostid{$clientip}     ne undef);
             );   my $ismanager=($managers{$clientip}    ne undef);
             &status("Connecting $clientip ($hostid{$clientip})");    $clientname  = "[unknonwn]";
             my $clientok;   if($clientrec) { # Establish client type.
             if ($clientrec) {      $ConnectionType = "client";
       &status("Waiting for init from $clientip ($hostid{$clientip})");      $clientname = $hostid{$clientip};
       my $remotereq=<$client>;      if($ismanager) {
               $remotereq=~s/[^\w:]//g;   $ConnectionType = "both";
               if ($remotereq =~ /^init/) {      }
   &sethost("sethost:$perlvar{'lonHostID'}");   } else {
   my $challenge="$$".time;      $ConnectionType = "manager";
                   print $client "$challenge\n";      $clientname = $managers{$clientip};
                   &status(   }
            "Waiting for challenge reply from $clientip ($hostid{$clientip})");    my $clientok;
                   $remotereq=<$client>;  
                   $remotereq=~s/\W//g;  
                   if ($challenge eq $remotereq) {  
       $clientok=1;  
                       print $client "ok\n";  
                   } else {  
       &logthis(  
  "<font color=blue>WARNING: $clientip did not reply challenge</font>");  
                       &status('No challenge reply '.$clientip);  
                   }  
               } else {  
   &logthis(  
                     "<font color=blue>WARNING: "  
                    ."$clientip failed to initialize: >$remotereq< </font>");  
                   &status('No init '.$clientip);  
               }  
     } else {  
               &logthis(  
  "<font color=blue>WARNING: Unknown client $clientip</font>");  
               &status('Hung up on '.$clientip);  
             }  
             if ($clientok) {  
 # ---------------- New known client connecting, could mean machine online again  
   
  foreach my $id (keys(%hostip)) {   if ($clientrec || $ismanager) {
     if ($hostip{$id} ne $clientip ||      &status("Waiting for init from $clientip $clientname");
        $hostip{$currenthostid} eq $clientip) {      &logthis('<font color="yellow">INFO: Connection, '.
  # no need to try to do recon's to myself       $clientip.
  next;    " ($clientname) connection type = $ConnectionType </font>" );
       &status("Connecting $clientip  ($clientname))"); 
       my $remotereq=<$client>;
       chomp($remotereq);
       Debug("Got init: $remotereq");
       my $inikeyword = split(/:/, $remotereq);
       if ($remotereq =~ /^init/) {
    &sethost("sethost:$perlvar{'lonHostID'}");
    #
    #  If the remote is attempting a local init... give that a try:
    #
    my ($i, $inittype) = split(/:/, $remotereq);
   
    # If the connection type is ssl, but I didn't get my
    # certificate files yet, then I'll drop  back to 
    # insecure (if allowed).
   
    if($inittype eq "ssl") {
       my ($ca, $cert) = lonssl::CertificateFile;
       my $kfile       = lonssl::KeyFile;
       if((!$ca)   || 
          (!$cert) || 
          (!$kfile)) {
    $inittype = ""; # This forces insecure attempt.
    &logthis("<font color=\"blue\"> Certificates not "
    ."installed -- trying insecure auth</font>");
     }      }
     &reconlonc("$perlvar{'lonSockDir'}/$id");      else { # SSL certificates are in place so
       } # Leave the inittype alone.
  }   }
  &logthis("<font color=green>Established connection: $hostid{$clientip}</font>");  
               &status('Will listen to '.$hostid{$clientip});   if($inittype eq "local") {
       my $key = LocalConnection($client, $remotereq);
       if($key) {
    Debug("Got local key $key");
    $clientok     = 1;
    my $cipherkey = pack("H32", $key);
    $cipher       = new IDEA($cipherkey);
    print $client "ok:local\n";
    &logthis('<font color="green"'
    . "Successful local authentication </font>");
    $keymode = "local"
       } else {
    Debug("Failed to get local key");
    $clientok = 0;
    shutdown($client, 3);
    close $client;
       }
    } elsif ($inittype eq "ssl") {
       my $key = SSLConnection($client);
       if ($key) {
    $clientok = 1;
    my $cipherkey = pack("H32", $key);
    $cipher       = new IDEA($cipherkey);
    &logthis('<font color="green">'
    ."Successfull ssl authentication with $clientname </font>");
    $keymode = "ssl";
        
       } else {
    $clientok = 0;
    close $client;
       }
      
    } else {
       my $ok = InsecureConnection($client);
       if($ok) {
    $clientok = 1;
    &logthis('<font color="green">'
    ."Successful insecure authentication with $clientname </font>");
    print $client "ok\n";
    $keymode = "insecure";
       } else {
    &logthis('<font color="yellow">'
     ."Attempted insecure connection disallowed </font>");
    close $client;
    $clientok = 0;
   
       }
    }
       } else {
    &logthis(
    "<font color='blue'>WARNING: "
    ."$clientip failed to initialize: >$remotereq< </font>");
    &status('No init '.$clientip);
       }
       
    } else {
       &logthis(
        "<font color='blue'>WARNING: Unknown client $clientip</font>");
       &status('Hung up on '.$clientip);
    }
    
    if ($clientok) {
   # ---------------- New known client connecting, could mean machine online again
       
       foreach my $id (keys(%hostip)) {
    if ($hostip{$id} ne $clientip ||
       $hostip{$currenthostid} eq $clientip) {
       # no need to try to do recon's to myself
       next;
    }
    &reconlonc("$perlvar{'lonSockDir'}/$id");
       }
       &logthis("<font color='green'>Established connection: $clientname</font>");
       &status('Will listen to '.$clientname);
 # ------------------------------------------------------------ Process requests  # ------------------------------------------------------------ Process requests
               while (my $userinput=<$client>) {      while (my $userinput=<$client>) {
                 chomp($userinput);                  chomp($userinput);
  Debug("Request = $userinput\n");   Debug("Request = $userinput\n");
                 &status('Processing '.$hostid{$clientip}.': '.$userinput);                  &status('Processing '.$clientname.': '.$userinput);
                 my $wasenc=0;                  my $wasenc=0;
                 alarm(120);                  alarm(120);
 # ------------------------------------------------------------ See if encrypted  # ------------------------------------------------------------ See if encrypted
  if ($userinput =~ /^enc/) {   if ($userinput =~ /^enc/) {
   if ($cipher) {      if ($cipher) {
                     my ($cmd,$cmdlength,$encinput)=split(/:/,$userinput);   my ($cmd,$cmdlength,$encinput)=split(/:/,$userinput);
     $userinput='';   $userinput='';
                     for (my $encidx=0;$encidx<length($encinput);$encidx+=16) {   for (my $encidx=0;$encidx<length($encinput);$encidx+=16) {
                        $userinput.=      $userinput.=
    $cipher->decrypt(   $cipher->decrypt(
                             pack("H16",substr($encinput,$encidx,16))   pack("H16",substr($encinput,$encidx,16))
                            );   );
    }
    $userinput=substr($userinput,0,$cmdlength);
    $wasenc=1;
     }      }
     $userinput=substr($userinput,0,$cmdlength);  
                     $wasenc=1;  
  }   }
       }  
     
 # ------------------------------------------------------------- Normal commands  # ------------------------------------------------------------- Normal commands
 # ------------------------------------------------------------------------ ping  # ------------------------------------------------------------------------ ping
    if ($userinput =~ /^ping/) {   if ($userinput =~ /^ping/) { # client only
                        print $client "$currenthostid\n";      if(isClient) {
    print $client "$currenthostid\n";
       } else {
    Reply($client, "refused\n", $userinput);
       }
 # ------------------------------------------------------------------------ pong  # ------------------------------------------------------------------------ pong
    }elsif ($userinput =~ /^pong/) {   }elsif ($userinput =~ /^pong/) { # client only
                        my $reply=&reply("ping",$hostid{$clientip});      if(isClient) {
                        print $client "$currenthostid:$reply\n";    my $reply=&reply("ping",$clientname);
    print $client "$currenthostid:$reply\n"; 
       } else {
    Reply($client, "refused\n", $userinput);
       }
 # ------------------------------------------------------------------------ ekey  # ------------------------------------------------------------------------ ekey
    } elsif ($userinput =~ /^ekey/) {   } elsif ($userinput =~ /^ekey/) { # ok for both clients & mgrs
                        my $buildkey=time.$$.int(rand 100000);      my $buildkey=time.$$.int(rand 100000);
                        $buildkey=~tr/1-6/A-F/;      $buildkey=~tr/1-6/A-F/;
                        $buildkey=int(rand 100000).$buildkey.int(rand 100000);      $buildkey=int(rand 100000).$buildkey.int(rand 100000);
                        my $key=$currenthostid.$hostid{$clientip};      my $key=$currenthostid.$clientname;
                        $key=~tr/a-z/A-Z/;      $key=~tr/a-z/A-Z/;
                        $key=~tr/G-P/0-9/;      $key=~tr/G-P/0-9/;
                        $key=~tr/Q-Z/0-9/;      $key=~tr/Q-Z/0-9/;
                        $key=$key.$buildkey.$key.$buildkey.$key.$buildkey;      $key=$key.$buildkey.$key.$buildkey.$key.$buildkey;
                        $key=substr($key,0,32);      $key=substr($key,0,32);
                        my $cipherkey=pack("H32",$key);      my $cipherkey=pack("H32",$key);
                        $cipher=new IDEA $cipherkey;      $cipher=new IDEA $cipherkey;
                        print $client "$buildkey\n";       print $client "$buildkey\n"; 
 # ------------------------------------------------------------------------ load  # ------------------------------------------------------------------------ load
    } elsif ($userinput =~ /^load/) {   } elsif ($userinput =~ /^load/) { # client only
                        my $loadavg;      if (isClient) {
                        {   my $loadavg;
                           my $loadfile=IO::File->new('/proc/loadavg');   {
                           $loadavg=<$loadfile>;      my $loadfile=IO::File->new('/proc/loadavg');
                        }      $loadavg=<$loadfile>;
                        $loadavg =~ s/\s.*//g;   }
        my $loadpercent=100*$loadavg/$perlvar{'lonLoadLim'};   $loadavg =~ s/\s.*//g;
        print $client "$loadpercent\n";   my $loadpercent=100*$loadavg/$perlvar{'lonLoadLim'};
    print $client "$loadpercent\n";
       } else {
    Reply($client, "refused\n", $userinput);
          
       }
 # -------------------------------------------------------------------- userload  # -------------------------------------------------------------------- userload
    } elsif ($userinput =~ /^userload/) {   } elsif ($userinput =~ /^userload/) { # client only
        my $userloadpercent=&userload();      if(isClient) {
        print $client "$userloadpercent\n";   my $userloadpercent=&userload();
    print $client "$userloadpercent\n";
       } else {
    Reply($client, "refused\n", $userinput);
        
       }
 #  #
 #        Transactions requiring encryption:  #        Transactions requiring encryption:
 #  #
 # ----------------------------------------------------------------- currentauth  # ----------------------------------------------------------------- currentauth
    } elsif ($userinput =~ /^currentauth/) {   } elsif ($userinput =~ /^currentauth/) {
      if ($wasenc==1) {      if (($wasenc==1)  && isClient) { # Encoded & client only.
                        my ($cmd,$udom,$uname)=split(/:/,$userinput);   my ($cmd,$udom,$uname)=split(/:/,$userinput);
        my $result = GetAuthType($udom, $uname);   my $result = GetAuthType($udom, $uname);
        if($result eq "nouser") {   if($result eq "nouser") {
    print $client "unknown_user\n";      print $client "unknown_user\n";
        }   }
        else {   else {
    print $client "$result\n"      print $client "$result\n"
        }      }
      } else {      } else {
        print $client "refused\n";   Reply($client, "refused\n", $userinput);
      }  
       }
 #--------------------------------------------------------------------- pushfile  #--------------------------------------------------------------------- pushfile
    } elsif($userinput =~ /^pushfile/) {    } elsif($userinput =~ /^pushfile/) { # encoded & manager.
        if($wasenc == 1) {      if(($wasenc == 1) && isManager) {
    my $cert = GetCertificate($userinput);   my $cert = GetCertificate($userinput);
    if(ValidManager($cert)) {   if(ValidManager($cert)) {
        my $reply = PushFile($userinput);      my $reply = PushFile($userinput);
        print $client "$reply\n";      print $client "$reply\n";
    } else {   } else {
        print $client "refused\n";      print $client "refused\n";
    }    } 
        } else {      } else {
    print $client "refused\n";   Reply($client, "refused\n", $userinput);
        }  
       }
 #--------------------------------------------------------------------- reinit  #--------------------------------------------------------------------- reinit
    } elsif($userinput =~ /^reinit/) {   } elsif($userinput =~ /^reinit/) { # Encoded and manager
        if ($wasenc == 1) {   if (($wasenc == 1) && isManager) {
    my $cert = GetCertificate($userinput);   my $cert = GetCertificate($userinput);
    if(ValidManager($cert)) {   if(ValidManager($cert)) {
        chomp($userinput);   chomp($userinput);
        my $reply = ReinitProcess($userinput);   my $reply = ReinitProcess($userinput);
        print $client  "$reply\n";   print $client  "$reply\n";
    } else {   } else {
        print $client "refused\n";   print $client "refused\n";
    }   }
        } else {   } else {
    print $client "refused\n";   Reply($client, "refused\n", $userinput);
        }   }
   #------------------------------------------------------------------------- edit
       } elsif ($userinput =~ /^edit/) {    # encoded and manager:
    if(($wasenc ==1) && (isManager)) {
       my $cert = GetCertificate($userinput);
       if(ValidManager($cert)) {
                  my($command, $filetype, $script) = split(/:/, $userinput);
                  if (($filetype eq "hosts") || ($filetype eq "domain")) {
                     if($script ne "") {
         Reply($client, EditFile($userinput));
                     } else {
                        Reply($client,"refused\n",$userinput);
                     }
                  } else {
                     Reply($client,"refused\n",$userinput);
                  }
               } else {
                  Reply($client,"refused\n",$userinput);
               }
            } else {
        Reply($client,"refused\n",$userinput);
    }
 # ------------------------------------------------------------------------ auth  # ------------------------------------------------------------------------ auth
                    } elsif ($userinput =~ /^auth/) {      } elsif ($userinput =~ /^auth/) { # Encoded and client only.
      if ($wasenc==1) {      if (($wasenc==1) && isClient) {
                        my ($cmd,$udom,$uname,$upass)=split(/:/,$userinput);   my ($cmd,$udom,$uname,$upass)=split(/:/,$userinput);
                        chomp($upass);   chomp($upass);
                        $upass=unescape($upass);   $upass=unescape($upass);
                        my $proname=propath($udom,$uname);   my $proname=propath($udom,$uname);
                        my $passfilename="$proname/passwd";   my $passfilename="$proname/passwd";
                        if (-e $passfilename) {   if (-e $passfilename) {
                           my $pf = IO::File->new($passfilename);      my $pf = IO::File->new($passfilename);
                           my $realpasswd=<$pf>;      my $realpasswd=<$pf>;
                           chomp($realpasswd);      chomp($realpasswd);
                           my ($howpwd,$contentpwd)=split(/:/,$realpasswd);      my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
                           my $pwdcorrect=0;      my $pwdcorrect=0;
                           if ($howpwd eq 'internal') {      if ($howpwd eq 'internal') {
       &Debug("Internal auth");   &Debug("Internal auth");
       $pwdcorrect=   $pwdcorrect=
   (crypt($upass,$contentpwd) eq $contentpwd);      (crypt($upass,$contentpwd) eq $contentpwd);
                           } elsif ($howpwd eq 'unix') {      } elsif ($howpwd eq 'unix') {
       &Debug("Unix auth");   &Debug("Unix auth");
                               if((getpwnam($uname))[1] eq "") { #no such user!   if((getpwnam($uname))[1] eq "") { #no such user!
   $pwdcorrect = 0;      $pwdcorrect = 0;
       } else {   } else {
   $contentpwd=(getpwnam($uname))[1];      $contentpwd=(getpwnam($uname))[1];
   my $pwauth_path="/usr/local/sbin/pwauth";      my $pwauth_path="/usr/local/sbin/pwauth";
   unless ($contentpwd eq 'x') {      unless ($contentpwd eq 'x') {
       $pwdcorrect=   $pwdcorrect=
   (crypt($upass,$contentpwd) eq       (crypt($upass,$contentpwd) eq 
    $contentpwd);       $contentpwd);
   }      }
         
       elsif (-e $pwauth_path) {      elsif (-e $pwauth_path) {
   open PWAUTH, "|$pwauth_path" or   open PWAUTH, "|$pwauth_path" or
       die "Cannot invoke authentication";      die "Cannot invoke authentication";
   print PWAUTH "$uname\n$upass\n";   print PWAUTH "$uname\n$upass\n";
   close PWAUTH;   close PWAUTH;
   $pwdcorrect=!$?;   $pwdcorrect=!$?;
       }      }
       }   }
                           } elsif ($howpwd eq 'krb4') {      } elsif ($howpwd eq 'krb4') {
                               my $null=pack("C",0);   my $null=pack("C",0);
                               unless ($upass=~/$null/) {   unless ($upass=~/$null/) {
                                   my $krb4_error = &Authen::Krb4::get_pw_in_tkt      my $krb4_error = &Authen::Krb4::get_pw_in_tkt
                                       ($uname,"",$contentpwd,'krbtgt',   ($uname,"",$contentpwd,'krbtgt',
                                        $contentpwd,1,$upass);   $contentpwd,1,$upass);
                                   if (!$krb4_error) {      if (!$krb4_error) {
                                       $pwdcorrect = 1;   $pwdcorrect = 1;
                                   } else {       } else { 
                                       $pwdcorrect=0;    $pwdcorrect=0; 
                                       # log error if it is not a bad password   # log error if it is not a bad password
                                       if ($krb4_error != 62) {   if ($krb4_error != 62) {
        &logthis('krb4:'.$uname.','.$contentpwd.','.      &logthis('krb4:'.$uname.','.
                 &Authen::Krb4::get_err_txt($Authen::Krb4::error));       &Authen::Krb4::get_err_txt($Authen::Krb4::error));
                                       }   }
                                   }      }
                               }   }
                           } elsif ($howpwd eq 'krb5') {      } elsif ($howpwd eq 'krb5') {
       my $null=pack("C",0);   my $null=pack("C",0);
       unless ($upass=~/$null/) {   unless ($upass=~/$null/) {
   my $krbclient=&Authen::Krb5::parse_name($uname.'@'.$contentpwd);      my $krbclient=&Authen::Krb5::parse_name($uname.'@'.$contentpwd);
   my $krbservice="krbtgt/".$contentpwd."\@".$contentpwd;      my $krbservice="krbtgt/".$contentpwd."\@".$contentpwd;
   my $krbserver=&Authen::Krb5::parse_name($krbservice);      my $krbserver=&Authen::Krb5::parse_name($krbservice);
   my $credentials=&Authen::Krb5::cc_default();      my $credentials=&Authen::Krb5::cc_default();
   $credentials->initialize($krbclient);      $credentials->initialize($krbclient);
   my $krbreturn =       my $krbreturn = 
     &Authen::Krb5::get_in_tkt_with_password(   &Authen::Krb5::get_in_tkt_with_password(
      $krbclient,$krbserver,$upass,$credentials);   $krbclient,$krbserver,$upass,$credentials);
 #  unless ($krbreturn) {  #  unless ($krbreturn) {
 #      &logthis("Krb5 Error: ".  #      &logthis("Krb5 Error: ".
 #       &Authen::Krb5::error());  #       &Authen::Krb5::error());
 #  }  #  }
   $pwdcorrect = ($krbreturn == 1);      $pwdcorrect = ($krbreturn == 1);
    } else { $pwdcorrect=0; }   } else { $pwdcorrect=0; }
                           } elsif ($howpwd eq 'localauth') {      } elsif ($howpwd eq 'localauth') {
     $pwdcorrect=&localauth::localauth($uname,$upass,   $pwdcorrect=&localauth::localauth($uname,$upass,
       $contentpwd);    $contentpwd);
   }      }
                           if ($pwdcorrect) {      if ($pwdcorrect) {
                              print $client "authorized\n";   print $client "authorized\n";
                           } else {      } else {
                              print $client "non_authorized\n";   print $client "non_authorized\n";
                           }        }  
        } else {   } else {
                           print $client "unknown_user\n";      print $client "unknown_user\n";
                        }   }
      } else {      } else {
        print $client "refused\n";   Reply($client, "refused\n", $userinput);
      }         
       }
 # ---------------------------------------------------------------------- passwd  # ---------------------------------------------------------------------- passwd
                    } elsif ($userinput =~ /^passwd/) {   } elsif ($userinput =~ /^passwd/) { # encoded and client
      if ($wasenc==1) {      if (($wasenc==1) && isClient) {
                        my    my 
                        ($cmd,$udom,$uname,$upass,$npass)=split(/:/,$userinput);      ($cmd,$udom,$uname,$upass,$npass)=split(/:/,$userinput);
                        chomp($npass);   chomp($npass);
                        $upass=&unescape($upass);   $upass=&unescape($upass);
                        $npass=&unescape($npass);   $npass=&unescape($npass);
        &Debug("Trying to change password for $uname");   &Debug("Trying to change password for $uname");
        my $proname=propath($udom,$uname);   my $proname=propath($udom,$uname);
                        my $passfilename="$proname/passwd";   my $passfilename="$proname/passwd";
                        if (-e $passfilename) {   if (-e $passfilename) {
    my $realpasswd;      my $realpasswd;
                           { my $pf = IO::File->new($passfilename);      { my $pf = IO::File->new($passfilename);
     $realpasswd=<$pf>; }        $realpasswd=<$pf>; }
                           chomp($realpasswd);      chomp($realpasswd);
                           my ($howpwd,$contentpwd)=split(/:/,$realpasswd);      my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
                           if ($howpwd eq 'internal') {      if ($howpwd eq 'internal') {
    &Debug("internal auth");   &Debug("internal auth");
    if (crypt($upass,$contentpwd) eq $contentpwd) {   if (crypt($upass,$contentpwd) eq $contentpwd) {
      my $salt=time;      my $salt=time;
                              $salt=substr($salt,6,2);      $salt=substr($salt,6,2);
      my $ncpass=crypt($npass,$salt);      my $ncpass=crypt($npass,$salt);
                              {      {
  my $pf;   my $pf;
  if ($pf = IO::File->new(">$passfilename")) {   if ($pf = IO::File->new(">$passfilename")) {
      print $pf "internal:$ncpass\n";      print $pf "internal:$ncpass\n";
      &logthis("Result of password change for $uname: pwchange_success");      &logthis("Result of password change for $uname: pwchange_success");
      print $client "ok\n";      print $client "ok\n";
  } else {   } else {
      &logthis("Unable to open $uname passwd to change password");      &logthis("Unable to open $uname passwd to change password");
      print $client "non_authorized\n";      print $client "non_authorized\n";
  }   }
      }                   }             
            
                            } else {   } else {
                              print $client "non_authorized\n";      print $client "non_authorized\n";
                            }   }
                           } elsif ($howpwd eq 'unix') {      } elsif ($howpwd eq 'unix') {
       # Unix means we have to access /etc/password   # Unix means we have to access /etc/password
       # one way or another.   # one way or another.
       # First: Make sure the current password is   # First: Make sure the current password is
       #        correct   #        correct
       &Debug("auth is unix");   &Debug("auth is unix");
       $contentpwd=(getpwnam($uname))[1];   $contentpwd=(getpwnam($uname))[1];
       my $pwdcorrect = "0";   my $pwdcorrect = "0";
       my $pwauth_path="/usr/local/sbin/pwauth";   my $pwauth_path="/usr/local/sbin/pwauth";
       unless ($contentpwd eq 'x') {   unless ($contentpwd eq 'x') {
   $pwdcorrect=      $pwdcorrect=
                                     (crypt($upass,$contentpwd) eq $contentpwd);   (crypt($upass,$contentpwd) eq $contentpwd);
       } elsif (-e $pwauth_path) {   } elsif (-e $pwauth_path) {
   open PWAUTH, "|$pwauth_path" or      open PWAUTH, "|$pwauth_path" or
       die "Cannot invoke authentication";   die "Cannot invoke authentication";
   print PWAUTH "$uname\n$upass\n";      print PWAUTH "$uname\n$upass\n";
   close PWAUTH;      close PWAUTH;
   &Debug("exited pwauth with $? ($uname,$upass) ");      &Debug("exited pwauth with $? ($uname,$upass) ");
   $pwdcorrect=($? == 0);      $pwdcorrect=($? == 0);
       }   }
      if ($pwdcorrect) {   if ($pwdcorrect) {
  my $execdir=$perlvar{'lonDaemons'};      my $execdir=$perlvar{'lonDaemons'};
  &Debug("Opening lcpasswd pipeline");      &Debug("Opening lcpasswd pipeline");
  my $pf = IO::File->new("|$execdir/lcpasswd > $perlvar{'lonDaemons'}/logs/lcpasswd.log");      my $pf = IO::File->new("|$execdir/lcpasswd > $perlvar{'lonDaemons'}/logs/lcpasswd.log");
  print $pf "$uname\n$npass\n$npass\n";      print $pf "$uname\n$npass\n$npass\n";
  close $pf;      close $pf;
  my $err = $?;      my $err = $?;
  my $result = ($err>0 ? 'pwchange_failure'       my $result = ($err>0 ? 'pwchange_failure' 
        : 'ok');    : 'ok');
  &logthis("Result of password change for $uname: ".      &logthis("Result of password change for $uname: ".
   &lcpasswdstrerror($?));       &lcpasswdstrerror($?));
  print $client "$result\n";      print $client "$result\n";
      } else {   } else {
  print $client "non_authorized\n";      print $client "non_authorized\n";
      }   }
   } else {      } else {
                             print $client "auth_mode_error\n";   print $client "auth_mode_error\n";
                           }        }  
        } else {   } else {
                           print $client "unknown_user\n";      print $client "unknown_user\n";
                        }   }
      } else {      } else {
        print $client "refused\n";   Reply($client, "refused\n", $userinput);
      }         
       }
 # -------------------------------------------------------------------- makeuser  # -------------------------------------------------------------------- makeuser
                    } elsif ($userinput =~ /^makeuser/) {   } elsif ($userinput =~ /^makeuser/) { # encoded and client.
      &Debug("Make user received");      &Debug("Make user received");
                 my $oldumask=umask(0077);      my $oldumask=umask(0077);
      if ($wasenc==1) {      if (($wasenc==1) && isClient) {
                        my    my 
                        ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);      ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);
        &Debug("cmd =".$cmd." $udom =".$udom.   &Debug("cmd =".$cmd." $udom =".$udom.
     " uname=".$uname);         " 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:".   &Debug("Password file created will be:".
     $passfilename);         $passfilename);
                        if (-e $passfilename) {   if (-e $passfilename) {
    print $client "already_exists\n";      print $client "already_exists\n";
                        } elsif ($udom ne $currentdomainid) {   } elsif ($udom ne $currentdomainid) {
                            print $client "not_right_domain\n";      print $client "not_right_domain\n";
                        } else {   } else {
                            my @fpparts=split(/\//,$proname);      my @fpparts=split(/\//,$proname);
                            my $fpnow=$fpparts[0].'/'.$fpparts[1].'/'.$fpparts[2];      my $fpnow=$fpparts[0].'/'.$fpparts[1].'/'.$fpparts[2];
                            my $fperror='';      my $fperror='';
                            for (my $i=3;$i<=$#fpparts;$i++) {      for (my $i=3;$i<=$#fpparts;$i++) {
                                $fpnow.='/'.$fpparts[$i];    $fpnow.='/'.$fpparts[$i]; 
                                unless (-e $fpnow) {   unless (-e $fpnow) {
    unless (mkdir($fpnow,0777)) {      unless (mkdir($fpnow,0777)) {
                                       $fperror="error: ".($!+0)   $fperror="error: ".($!+0)
   ." mkdir failed while attempting "      ." mkdir failed while attempting "
                                               ."makeuser\n";      ."makeuser";
                                    }      }
                                }   }
                            }      }
                            unless ($fperror) {      unless ($fperror) {
        my $result=&make_passwd_file($uname, $umode,$npass,   my $result=&make_passwd_file($uname, $umode,$npass,
     $passfilename);       $passfilename);
        print $client $result;   print $client $result;
                            } else {      } else {
                                print $client "$fperror\n";   print $client "$fperror\n";
                            }      }
                        }   }
      } else {      } else {
        print $client "refused\n";   Reply($client, "refused\n", $userinput);
      }        
      umask($oldumask);      }
       umask($oldumask);
 # -------------------------------------------------------------- changeuserauth  # -------------------------------------------------------------- changeuserauth
                    } elsif ($userinput =~ /^changeuserauth/) {   } elsif ($userinput =~ /^changeuserauth/) { # encoded & client
        &Debug("Changing authorization");      &Debug("Changing authorization");
       if ($wasenc==1) {      if (($wasenc==1) && isClient) {
                        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.   &Debug("cmd = ".$cmd." domain= ".$udom.
       "uname =".$uname." umode= ".$umode);         "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";
        if ($udom ne $currentdomainid) {   if ($udom ne $currentdomainid) {
                            print $client "not_right_domain\n";      print $client "not_right_domain\n";
                        } else {   } else {
    my $result=&make_passwd_file($uname, $umode,$npass,      my $result=&make_passwd_file($uname, $umode,$npass,
  $passfilename);   $passfilename);
    print $client $result;      print $client $result;
                        }   }
      } else {      } else {
        print $client "refused\n";   Reply($client, "refused\n", $userinput);
      }     
       }
 # ------------------------------------------------------------------------ home  # ------------------------------------------------------------------------ home
                    } elsif ($userinput =~ /^home/) {   } elsif ($userinput =~ /^home/) { # client clear or encoded
                        my ($cmd,$udom,$uname)=split(/:/,$userinput);      if(isClient) {
                        chomp($uname);   my ($cmd,$udom,$uname)=split(/:/,$userinput);
                        my $proname=propath($udom,$uname);   chomp($uname);
                        if (-e $proname) {   my $proname=propath($udom,$uname);
                           print $client "found\n";   if (-e $proname) {
                        } else {      print $client "found\n";
   print $client "not_found\n";   } else {
                        }      print $client "not_found\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
   
       }
 # ---------------------------------------------------------------------- update  # ---------------------------------------------------------------------- update
                    } elsif ($userinput =~ /^update/) {   } elsif ($userinput =~ /^update/) { # client clear or encoded.
                        my ($cmd,$fname)=split(/:/,$userinput);      if(isClient) {
                        my $ownership=ishome($fname);   my ($cmd,$fname)=split(/:/,$userinput);
                        if ($ownership eq 'not_owner') {   my $ownership=ishome($fname);
                         if (-e $fname) {   if ($ownership eq 'not_owner') {
                           my ($dev,$ino,$mode,$nlink,      if (-e $fname) {
                               $uid,$gid,$rdev,$size,   my ($dev,$ino,$mode,$nlink,
                               $atime,$mtime,$ctime,      $uid,$gid,$rdev,$size,
                               $blksize,$blocks)=stat($fname);      $atime,$mtime,$ctime,
                           my $now=time;      $blksize,$blocks)=stat($fname);
                           my $since=$now-$atime;   my $now=time;
                           if ($since>$perlvar{'lonExpire'}) {   my $since=$now-$atime;
                               my $reply=   if ($since>$perlvar{'lonExpire'}) {
                                     &reply("unsub:$fname","$hostid{$clientip}");      my $reply=
                               unlink("$fname");   &reply("unsub:$fname","$clientname");
                           } else {      unlink("$fname");
      my $transname="$fname.in.transfer";   } else {
                              my $remoteurl=      my $transname="$fname.in.transfer";
                                     reply("sub:$fname","$hostid{$clientip}");      my $remoteurl=
                              my $response;   &reply("sub:$fname","$clientname");
                               {      my $response;
                              my $ua=new LWP::UserAgent;      {
                              my $request=new HTTP::Request('GET',"$remoteurl");   my $ua=new LWP::UserAgent;
                              $response=$ua->request($request,$transname);   my $request=new HTTP::Request('GET',"$remoteurl");
       }   $response=$ua->request($request,$transname);
                              if ($response->is_error()) {      }
  unlink($transname);      if ($response->is_error()) {
                                  my $message=$response->status_line;   unlink($transname);
                                  &logthis(   my $message=$response->status_line;
                                   "LWP GET: $message for $fname ($remoteurl)");   &logthis(
                              } else {   "LWP GET: $message for $fname ($remoteurl)");
                          if ($remoteurl!~/\.meta$/) {      } else {
                                   my $ua=new LWP::UserAgent;   if ($remoteurl!~/\.meta$/) {
                                   my $mrequest=      my $ua=new LWP::UserAgent;
                                    new HTTP::Request('GET',$remoteurl.'.meta');      my $mrequest=
                                   my $mresponse=   new HTTP::Request('GET',$remoteurl.'.meta');
                                    $ua->request($mrequest,$fname.'.meta');      my $mresponse=
                                   if ($mresponse->is_error()) {   $ua->request($mrequest,$fname.'.meta');
                     unlink($fname.'.meta');      if ($mresponse->is_error()) {
                                   }   unlink($fname.'.meta');
                          }      }
                                  rename($transname,$fname);   }
      }   rename($transname,$fname);
                           }      }
                           print $client "ok\n";   }
                         } else {   print $client "ok\n";
                           print $client "not_found\n";      } else {
                         }   print $client "not_found\n";
        } else {      }
  print $client "rejected\n";   } else {
                        }      print $client "rejected\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
   
       }
 # -------------------------------------- fetch a user file from a remote server  # -------------------------------------- fetch a user file from a remote server
                    } elsif ($userinput =~ /^fetchuserfile/) {   } elsif ($userinput =~ /^fetchuserfile/) { # Client clear or enc.
        my ($cmd,$fname)=split(/:/,$userinput);      if(isClient) {
        my ($udom,$uname,$ufile)=split(/\//,$fname);   my ($cmd,$fname)=split(/:/,$userinput);
        my $udir=propath($udom,$uname).'/userfiles';   my ($udom,$uname,$ufile) = ($fname =~ m|^([^/]+)/([^/]+)/(.+)$|);
        unless (-e $udir) { mkdir($udir,0770); }   my $udir=propath($udom,$uname).'/userfiles';
                        if (-e $udir) {   unless (-e $udir) { mkdir($udir,0770); }
    $ufile=~s/^[\.\~]+//;   if (-e $udir) {
    $ufile=~s/\///g;                              $ufile=~s/^[\.\~]+//;
    my $destname=$udir.'/'.$ufile;                              my $path = $udir;
    my $transname=$udir.'/'.$ufile.'.in.transit';                              if ($ufile =~m|(.+)/([^/]+)$|) {
    my $remoteurl='http://'.$clientip.'/userfiles/'.$fname;                                  my @parts=split('/',$1);
    my $response;                                  foreach my $part (@parts) {
    {                                      $path .= '/'.$part;
        my $ua=new LWP::UserAgent;                                      if ((-e $path)!=1) {
        my $request=new HTTP::Request('GET',"$remoteurl");                                          mkdir($path,0770);
        $response=$ua->request($request,$transname);                                      }
    }                                  }
    if ($response->is_error()) {                              }
        unlink($transname);      my $destname=$udir.'/'.$ufile;
        my $message=$response->status_line;      my $transname=$udir.'/'.$ufile.'.in.transit';
        &logthis("LWP GET: $message for $fname ($remoteurl)");      my $remoteurl='http://'.$clientip.'/userfiles/'.$fname;
        print $client "failed\n";      my $response;
    } else {      {
        if (!rename($transname,$destname)) {   my $ua=new LWP::UserAgent;
    &logthis("Unable to move $transname to $destname");   my $request=new HTTP::Request('GET',"$remoteurl");
    unlink($transname);   $response=$ua->request($request,$transname);
    print $client "failed\n";      }
        } else {      if ($response->is_error()) {
    print $client "ok\n";   unlink($transname);
        }   my $message=$response->status_line;
    }   &logthis("LWP GET: $message for $fname ($remoteurl)");
        } else {   print $client "failed\n";
    print $client "not_home\n";      } else {
        }   if (!rename($transname,$destname)) {
       &logthis("Unable to move $transname to $destname");
       unlink($transname);
       print $client "failed\n";
    } else {
       print $client "ok\n";
    }
       }
    } else {
       print $client "not_home\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
       }
   # --------------------------------------------------------- remove a user file 
    } elsif ($userinput =~ /^removeuserfile/) { # Client clear or enc.
       if(isClient) {
    my ($cmd,$fname)=split(/:/,$userinput);
    my ($udom,$uname,$ufile) = ($fname =~ m|^([^/]+)/([^/]+)/(.+)$|);
    &logthis("$udom - $uname - $ufile");
    if ($ufile =~m|/\.\./|) {
       # any files paths with /../ in them refuse 
                               # to deal with
       print $client "refused\n";
    } else {
       my $udir=propath($udom,$uname);
       if (-e $udir) {
    my $file=$udir.'/userfiles/'.$ufile;
    if (-e $file) {
       unlink($file);
       if (-e $file) {
    print $client "failed\n";
       } else {
    print $client "ok\n";
       }
    } else {
       print $client "not_found\n";
    }
       } else {
    print $client "not_home\n";
       }
    }
       } else {
    Reply($client, "refused\n", $userinput);
       }
 # ------------------------------------------ authenticate access to a user file  # ------------------------------------------ authenticate access to a user file
                    } elsif ($userinput =~ /^tokenauthuserfile/) {   } elsif ($userinput =~ /^tokenauthuserfile/) { # Client only
                        my ($cmd,$fname,$session)=split(/:/,$userinput);      if(isClient) {
                        chomp($session);   my ($cmd,$fname,$session)=split(/:/,$userinput);
                        my $reply='non_auth';   chomp($session);
                        if (open(ENVIN,$perlvar{'lonIDsDir'}.'/'.   my $reply='non_auth';
  $session.'.id')) {   if (open(ENVIN,$perlvar{'lonIDsDir'}.'/'.
    while (my $line=<ENVIN>) {   $session.'.id')) {
        if ($line=~/userfile\.$fname\=/) { $reply='ok'; }      while (my $line=<ENVIN>) {
    }   if ($line=~ m|userfile\.\Q$fname\E\=|) { $reply='ok'; }
    close(ENVIN);      }
    print $client $reply."\n";      close(ENVIN);
        } else {      print $client $reply."\n";
    print $client "invalid_token\n";   } else {
                        }      print $client "invalid_token\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
   
       }
 # ----------------------------------------------------------------- unsubscribe  # ----------------------------------------------------------------- unsubscribe
                    } elsif ($userinput =~ /^unsub/) {   } elsif ($userinput =~ /^unsub/) {
                        my ($cmd,$fname)=split(/:/,$userinput);      if(isClient) {
                        if (-e $fname) {   my ($cmd,$fname)=split(/:/,$userinput);
    print $client &unsub($client,$fname,$clientip);   if (-e $fname) {
                        } else {      print $client &unsub($fname,$clientip);
    print $client "not_found\n";   } else {
                        }      print $client "not_found\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
   
       }
 # ------------------------------------------------------------------- subscribe  # ------------------------------------------------------------------- subscribe
                    } elsif ($userinput =~ /^sub/) {   } elsif ($userinput =~ /^sub/) {
        print $client &subscribe($userinput,$clientip);      if(isClient) {
    print $client &subscribe($userinput,$clientip);
       } else {
    Reply($client, "refused\n", $userinput);
   
       }
 # ------------------------------------------------------------- current version  # ------------------------------------------------------------- current version
                    } elsif ($userinput =~ /^currentversion/) {   } elsif ($userinput =~ /^currentversion/) {
                        my ($cmd,$fname)=split(/:/,$userinput);      if(isClient) {
        print $client &currentversion($fname)."\n";   my ($cmd,$fname)=split(/:/,$userinput);
    print $client &currentversion($fname)."\n";
       } else {
    Reply($client, "refused\n", $userinput);
   
       }
 # ------------------------------------------------------------------------- log  # ------------------------------------------------------------------------- log
                    } elsif ($userinput =~ /^log/) {   } elsif ($userinput =~ /^log/) {
                        my ($cmd,$udom,$uname,$what)=split(/:/,$userinput);      if(isClient) {
                        chomp($what);   my ($cmd,$udom,$uname,$what)=split(/:/,$userinput);
                        my $proname=propath($udom,$uname);   chomp($what);
                        my $now=time;   my $proname=propath($udom,$uname);
                        {   my $now=time;
  my $hfh;   {
  if ($hfh=IO::File->new(">>$proname/activity.log")) {       my $hfh;
                             print $hfh "$now:$hostid{$clientip}:$what\n";      if ($hfh=IO::File->new(">>$proname/activity.log")) { 
                             print $client "ok\n";    print $hfh "$now:$clientname:$what\n";
  } else {   print $client "ok\n"; 
                             print $client "error: ".($!+0)      } else {
  ." IO::File->new Failed "   print $client "error: ".($!+0)
                                     ."while attempting log\n";      ." IO::File->new Failed "
         }      ."while attempting log\n";
        }      }
    }
       } else {
    Reply($client, "refused\n", $userinput);
   
       }
 # ------------------------------------------------------------------------- put  # ------------------------------------------------------------------------- put
                    } elsif ($userinput =~ /^put/) {   } elsif ($userinput =~ /^put/) {
                       my ($cmd,$udom,$uname,$namespace,$what)      if(isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$uname,$namespace,$what)
                       $namespace=~s/\//\_/g;      =split(/:/,$userinput,5);
                       $namespace=~s/\W//g;   $namespace=~s/\//\_/g;
                       if ($namespace ne 'roles') {   $namespace=~s/\W//g;
                        chomp($what);   if ($namespace ne 'roles') {
                        my $proname=propath($udom,$uname);      chomp($what);
                        my $now=time;      my $proname=propath($udom,$uname);
                        unless ($namespace=~/^nohist\_/) {      my $now=time;
    my $hfh;      my @pairs=split(/\&/,$what);
    if (      my %hash;
                              $hfh=IO::File->new(">>$proname/$namespace.hist")      if (tie(%hash,'GDBM_File',
        ) { print $hfh "P:$now:$what\n"; }      "$proname/$namespace.db",
        }      &GDBM_WRCREAT(),0640)) {
                        my @pairs=split(/\&/,$what);   unless ($namespace=~/^nohist\_/) {
        my %hash;      my $hfh;
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {      if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { print $hfh "P:$now:$what\n"; }
                            foreach my $pair (@pairs) {   }
        my ($key,$value)=split(/=/,$pair);  
                                $hash{$key}=$value;   foreach my $pair (@pairs) {
                            }      my ($key,$value)=split(/=/,$pair);
    if (untie(%hash)) {      $hash{$key}=$value;
                               print $client "ok\n";   }
                            } else {   if (untie(%hash)) {
                               print $client "error: ".($!+0)      print $client "ok\n";
   ." untie(GDBM) failed ".   } else {
                                       "while attempting put\n";      print $client "error: ".($!+0)
                            }   ." untie(GDBM) failed ".
                        } else {   "while attempting put\n";
                            print $client "error: ".($!)   }
        ." tie(GDBM) Failed ".      } else {
                                    "while attempting put\n";   print $client "error: ".($!)
                        }      ." tie(GDBM) Failed ".
       } else {      "while attempting put\n";
                           print $client "refused\n";      }
                       }   } else {
       print $client "refused\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
   
       }
   # ------------------------------------------------------------------- inc
    } elsif ($userinput =~ /^inc:/) {
       if(isClient) {
    my ($cmd,$udom,$uname,$namespace,$what)
       =split(/:/,$userinput);
    $namespace=~s/\//\_/g;
    $namespace=~s/\W//g;
    if ($namespace ne 'roles') {
       chomp($what);
       my $proname=propath($udom,$uname);
       my $now=time;
       my @pairs=split(/\&/,$what);
       my %hash;
       if (tie(%hash,'GDBM_File',
       "$proname/$namespace.db",
       &GDBM_WRCREAT(),0640)) {
    unless ($namespace=~/^nohist\_/) {
       my $hfh;
       if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { print $hfh "P:$now:$what\n"; }
    }
    foreach my $pair (@pairs) {
       my ($key,$value)=split(/=/,$pair);
                                       # We could check that we have a number...
                                       if (! defined($value) || $value eq '') {
                                           $value = 1;
                                       }
       $hash{$key}+=$value;
    }
    if (untie(%hash)) {
       print $client "ok\n";
    } else {
       print $client "error: ".($!+0)
    ." untie(GDBM) failed ".
    "while attempting inc\n";
    }
       } else {
    print $client "error: ".($!)
       ." tie(GDBM) Failed ".
       "while attempting inc\n";
       }
    } else {
       print $client "refused\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
   
       }
 # -------------------------------------------------------------------- rolesput  # -------------------------------------------------------------------- rolesput
                    } elsif ($userinput =~ /^rolesput/) {   } elsif ($userinput =~ /^rolesput/) {
        &Debug("rolesput");      if(isClient) {
     if ($wasenc==1) {   &Debug("rolesput");
                        my ($cmd,$exedom,$exeuser,$udom,$uname,$what)   if ($wasenc==1) {
                           =split(/:/,$userinput);      my ($cmd,$exedom,$exeuser,$udom,$uname,$what)
        &Debug("cmd = ".$cmd." exedom= ".$exedom.   =split(/:/,$userinput);
     "user = ".$exeuser." udom=".$udom.      &Debug("cmd = ".$cmd." exedom= ".$exedom.
     "what = ".$what);     "user = ".$exeuser." udom=".$udom.
                        my $namespace='roles';     "what = ".$what);
                        chomp($what);      my $namespace='roles';
                        my $proname=propath($udom,$uname);      chomp($what);
                        my $now=time;      my $proname=propath($udom,$uname);
                        {      my $now=time;
    my $hfh;      my @pairs=split(/\&/,$what);
    if (      my %hash;
                              $hfh=IO::File->new(">>$proname/$namespace.hist")      if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
        ) {    {
                                   print $hfh "P:$now:$exedom:$exeuser:$what\n";      my $hfh;
                                  }      if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { 
        }   print $hfh "P:$now:$exedom:$exeuser:$what\n";
                        my @pairs=split(/\&/,$what);      }
        my %hash;   }
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {  
                            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,          &GetAuthType( $udom, 
  $uname));       $uname));
                                $hash{$key}=$value;      $hash{$key}=$value;
                            }   }
    if (untie(%hash)) {   if (untie(%hash)) {
                               print $client "ok\n";      print $client "ok\n";
                            } else {   } else {
                               print $client "error: ".($!+0)      print $client "error: ".($!+0)
   ." untie(GDBM) Failed ".   ." untie(GDBM) Failed ".
                                       "while attempting rolesput\n";   "while attempting rolesput\n";
                            }   }
                        } else {      } else {
                            print $client "error: ".($!+0)   print $client "error: ".($!+0)
        ." tie(GDBM) Failed ".      ." tie(GDBM) Failed ".
                                    "while attempting rolesput\n";      "while attempting rolesput\n";
                        }      }
       } else {   } else {
                           print $client "refused\n";      print $client "refused\n";
                       }   }
       } else {
    Reply($client, "refused\n", $userinput);
     
       }
 # -------------------------------------------------------------------- rolesdel  # -------------------------------------------------------------------- rolesdel
                    } elsif ($userinput =~ /^rolesdel/) {   } elsif ($userinput =~ /^rolesdel/) {
        &Debug("rolesdel");      if(isClient) {
     if ($wasenc==1) {   &Debug("rolesdel");
                        my ($cmd,$exedom,$exeuser,$udom,$uname,$what)   if ($wasenc==1) {
                           =split(/:/,$userinput);      my ($cmd,$exedom,$exeuser,$udom,$uname,$what)
        &Debug("cmd = ".$cmd." exedom= ".$exedom.   =split(/:/,$userinput);
     "user = ".$exeuser." udom=".$udom.      &Debug("cmd = ".$cmd." exedom= ".$exedom.
     "what = ".$what);     "user = ".$exeuser." udom=".$udom.
                        my $namespace='roles';     "what = ".$what);
                        chomp($what);      my $namespace='roles';
                        my $proname=propath($udom,$uname);      chomp($what);
                        my $now=time;      my $proname=propath($udom,$uname);
                        {      my $now=time;
    my $hfh;      my @rolekeys=split(/\&/,$what);
    if (      my %hash;
                              $hfh=IO::File->new(">>$proname/$namespace.hist")      if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
        ) {    {
                                   print $hfh "D:$now:$exedom:$exeuser:$what\n";      my $hfh;
                                  }      if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { 
        }   print $hfh "D:$now:$exedom:$exeuser:$what\n";
                        my @rolekeys=split(/\&/,$what);      }
        my %hash;   }
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {   foreach my $key (@rolekeys) {
                            foreach my $key (@rolekeys) {      delete $hash{$key};
                                delete $hash{$key};   }
                            }   if (untie(%hash)) {
    if (untie(%hash)) {      print $client "ok\n";
                               print $client "ok\n";   } else {
                            } else {      print $client "error: ".($!+0)
                               print $client "error: ".($!+0)   ." untie(GDBM) Failed ".
   ." untie(GDBM) Failed ".   "while attempting rolesdel\n";
                                       "while attempting rolesdel\n";   }
                            }      } else {
                        } else {   print $client "error: ".($!+0)
                            print $client "error: ".($!+0)      ." tie(GDBM) Failed ".
        ." tie(GDBM) Failed ".      "while attempting rolesdel\n";
                                    "while attempting rolesdel\n";      }
                        }   } else {
       } else {      print $client "refused\n";
                           print $client "refused\n";   }
                       }      } else {
    Reply($client, "refused\n", $userinput);
         
       }
 # ------------------------------------------------------------------------- get  # ------------------------------------------------------------------------- get
                    } elsif ($userinput =~ /^get/) {   } elsif ($userinput =~ /^get/) {
                        my ($cmd,$udom,$uname,$namespace,$what)      if(isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$uname,$namespace,$what)
                        $namespace=~s/\//\_/g;      =split(/:/,$userinput);
                        $namespace=~s/\W//g;   $namespace=~s/\//\_/g;
                        chomp($what);   $namespace=~s/\W//g;
                        my @queries=split(/\&/,$what);   chomp($what);
                        my $proname=propath($udom,$uname);   my @queries=split(/\&/,$what);
                        my $qresult='';   my $proname=propath($udom,$uname);
        my %hash;   my $qresult='';
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {   my %hash;
                            for (my $i=0;$i<=$#queries;$i++) {   if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                                $qresult.="$hash{$queries[$i]}&";      for (my $i=0;$i<=$#queries;$i++) {
                            }   $qresult.="$hash{$queries[$i]}&";
    if (untie(%hash)) {      }
               $qresult=~s/\&$//;      if (untie(%hash)) {
                               print $client "$qresult\n";   $qresult=~s/\&$//;
                            } else {   print $client "$qresult\n";
                               print $client "error: ".($!+0)      } else {
   ." untie(GDBM) Failed ".   print $client "error: ".($!+0)
                                       "while attempting get\n";      ." untie(GDBM) Failed ".
                            }      "while attempting get\n";
                        } else {      }
                            if ($!+0 == 2) {   } else {
                                print $client "error:No such file or ".      if ($!+0 == 2) {
                                    "GDBM reported bad block error\n";   print $client "error:No such file or ".
                            } else {      "GDBM reported bad block error\n";
                                print $client "error: ".($!+0)      } else {
                                    ." tie(GDBM) Failed ".   print $client "error: ".($!+0)
                                        "while attempting get\n";      ." tie(GDBM) Failed ".
                            }      "while attempting get\n";
                        }      }
    }
       } else {
    Reply($client, "refused\n", $userinput);
          
       }
 # ------------------------------------------------------------------------ eget  # ------------------------------------------------------------------------ eget
                    } elsif ($userinput =~ /^eget/) {   } elsif ($userinput =~ /^eget/) {
                        my ($cmd,$udom,$uname,$namespace,$what)      if (isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$uname,$namespace,$what)
                        $namespace=~s/\//\_/g;      =split(/:/,$userinput);
                        $namespace=~s/\W//g;   $namespace=~s/\//\_/g;
                        chomp($what);   $namespace=~s/\W//g;
                        my @queries=split(/\&/,$what);   chomp($what);
                        my $proname=propath($udom,$uname);   my @queries=split(/\&/,$what);
                        my $qresult='';   my $proname=propath($udom,$uname);
        my %hash;   my $qresult='';
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {   my %hash;
                            for (my $i=0;$i<=$#queries;$i++) {   if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                                $qresult.="$hash{$queries[$i]}&";      for (my $i=0;$i<=$#queries;$i++) {
                            }   $qresult.="$hash{$queries[$i]}&";
    if (untie(%hash)) {      }
               $qresult=~s/\&$//;      if (untie(%hash)) {
                               if ($cipher) {   $qresult=~s/\&$//;
                                 my $cmdlength=length($qresult);   if ($cipher) {
                                 $qresult.="         ";      my $cmdlength=length($qresult);
                                 my $encqresult='';      $qresult.="         ";
                                 for       my $encqresult='';
  (my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {      for 
                                  $encqresult.=   (my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
                                  unpack("H16",      $encqresult.=
                                  $cipher->encrypt(substr($qresult,$encidx,8)));   unpack("H16",
                                 }         $cipher->encrypt(substr($qresult,$encidx,8)));
                                 print $client "enc:$cmdlength:$encqresult\n";   }
       } else {      print $client "enc:$cmdlength:$encqresult\n";
         print $client "error:no_key\n";   } else {
                               }      print $client "error:no_key\n";
                            } else {   }
                               print $client "error: ".($!+0)      } else {
   ." untie(GDBM) Failed ".   print $client "error: ".($!+0)
                                       "while attempting eget\n";      ." untie(GDBM) Failed ".
                            }      "while attempting eget\n";
                        } else {      }
                            print $client "error: ".($!+0)   } else {
        ." tie(GDBM) Failed ".      print $client "error: ".($!+0)
                                    "while attempting eget\n";   ." tie(GDBM) Failed ".
                        }   "while attempting eget\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
       
       }
 # ------------------------------------------------------------------------- del  # ------------------------------------------------------------------------- del
                    } elsif ($userinput =~ /^del/) {   } elsif ($userinput =~ /^del/) {
                        my ($cmd,$udom,$uname,$namespace,$what)      if(isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$uname,$namespace,$what)
                        $namespace=~s/\//\_/g;      =split(/:/,$userinput);
                        $namespace=~s/\W//g;   $namespace=~s/\//\_/g;
                        chomp($what);   $namespace=~s/\W//g;
                        my $proname=propath($udom,$uname);   chomp($what);
                        my $now=time;   my $proname=propath($udom,$uname);
                        unless ($namespace=~/^nohist\_/) {   my $now=time;
    my $hfh;   my @keys=split(/\&/,$what);
    if (   my %hash;
                              $hfh=IO::File->new(">>$proname/$namespace.hist")   if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
        ) { print $hfh "D:$now:$what\n"; }      unless ($namespace=~/^nohist\_/) {
        }   my $hfh;
                        my @keys=split(/\&/,$what);   if ($hfh=IO::File->new(">>$proname/$namespace.hist")) { print $hfh "D:$now:$what\n"; }
        my %hash;      }
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {      foreach my $key (@keys) {
                            foreach my $key (@keys) {   delete($hash{$key});
                                delete($hash{$key});      }
                            }      if (untie(%hash)) {
    if (untie(%hash)) {   print $client "ok\n";
                               print $client "ok\n";      } else {
                            } else {   print $client "error: ".($!+0)
                               print $client "error: ".($!+0)      ." untie(GDBM) Failed ".
   ." untie(GDBM) Failed ".      "while attempting del\n";
                                       "while attempting del\n";      }
                            }   } else {
                        } else {      print $client "error: ".($!+0)
                            print $client "error: ".($!+0)   ." tie(GDBM) Failed ".
        ." tie(GDBM) Failed ".   "while attempting del\n";
                                    "while attempting del\n";   }
                        }      } else {
    Reply($client, "refused\n", $userinput);
   
       }
 # ------------------------------------------------------------------------ keys  # ------------------------------------------------------------------------ keys
                    } elsif ($userinput =~ /^keys/) {   } elsif ($userinput =~ /^keys/) {
                        my ($cmd,$udom,$uname,$namespace)      if(isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$uname,$namespace)
                        $namespace=~s/\//\_/g;      =split(/:/,$userinput);
                        $namespace=~s/\W//g;   $namespace=~s/\//\_/g;
                        my $proname=propath($udom,$uname);   $namespace=~s/\W//g;
                        my $qresult='';   my $proname=propath($udom,$uname);
        my %hash;   my $qresult='';
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {   my %hash;
                            foreach my $key (keys %hash) {   if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                                $qresult.="$key&";      foreach my $key (keys %hash) {
                            }   $qresult.="$key&";
    if (untie(%hash)) {      }
               $qresult=~s/\&$//;      if (untie(%hash)) {
                               print $client "$qresult\n";   $qresult=~s/\&$//;
                            } else {   print $client "$qresult\n";
                               print $client "error: ".($!+0)      } else {
   ." untie(GDBM) Failed ".   print $client "error: ".($!+0)
                                       "while attempting keys\n";      ." untie(GDBM) Failed ".
                            }      "while attempting keys\n";
                        } else {      }
                            print $client "error: ".($!+0)   } else {
        ." tie(GDBM) Failed ".      print $client "error: ".($!+0)
                                    "while attempting keys\n";   ." tie(GDBM) Failed ".
                        }   "while attempting keys\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
      
       }
 # ----------------------------------------------------------------- dumpcurrent  # ----------------------------------------------------------------- dumpcurrent
                    } elsif ($userinput =~ /^currentdump/) {   } elsif ($userinput =~ /^currentdump/) {
                        my ($cmd,$udom,$uname,$namespace)      if (isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$uname,$namespace)
                        $namespace=~s/\//\_/g;      =split(/:/,$userinput);
                        $namespace=~s/\W//g;   $namespace=~s/\//\_/g;
                        my $qresult='';   $namespace=~s/\W//g;
                        my $proname=propath($udom,$uname);   my $qresult='';
        my %hash;   my $proname=propath($udom,$uname);
                        if (tie(%hash,'GDBM_File',   my %hash;
                                "$proname/$namespace.db",   if (tie(%hash,'GDBM_File',
                                &GDBM_READER(),0640)) {   "$proname/$namespace.db",
                            # Structure of %data:   &GDBM_READER(),0640)) {
                            # $data{$symb}->{$parameter}=$value;      # Structure of %data:
                            # $data{$symb}->{'v.'.$parameter}=$version;      # $data{$symb}->{$parameter}=$value;
                            # since $parameter will be unescaped, we do not      # $data{$symb}->{'v.'.$parameter}=$version;
                            # have to worry about silly parameter names...      # since $parameter will be unescaped, we do not
                            my %data = ();      # have to worry about silly parameter names...
                            while (my ($key,$value) = each(%hash)) {      my %data = ();
                               my ($v,$symb,$param) = split(/:/,$key);      while (my ($key,$value) = each(%hash)) {
                               next if ($v eq 'version' || $symb eq 'keys');   my ($v,$symb,$param) = split(/:/,$key);
                               next if (exists($data{$symb}) &&    next if ($v eq 'version' || $symb eq 'keys');
                                        exists($data{$symb}->{$param}) &&   next if (exists($data{$symb}) && 
                                        $data{$symb}->{'v.'.$param} > $v);   exists($data{$symb}->{$param}) &&
                               $data{$symb}->{$param}=$value;   $data{$symb}->{'v.'.$param} > $v);
                               $data{$symb}->{'v.'.$param}=$v;   $data{$symb}->{$param}=$value;
                            }   $data{$symb}->{'v.'.$param}=$v;
                            if (untie(%hash)) {      }
                              while (my ($symb,$param_hash) = each(%data)) {      if (untie(%hash)) {
                                while(my ($param,$value) = each (%$param_hash)){   while (my ($symb,$param_hash) = each(%data)) {
                                  next if ($param =~ /^v\./);      while(my ($param,$value) = each (%$param_hash)){
                                  $qresult.=$symb.':'.$param.'='.$value.'&';   next if ($param =~ /^v\./);
                                }   $qresult.=$symb.':'.$param.'='.$value.'&';
                              }      }
                              chop($qresult);   }
                              print $client "$qresult\n";   chop($qresult);
                            } else {   print $client "$qresult\n";
                              print $client "error: ".($!+0)      } else {
  ." untie(GDBM) Failed ".   print $client "error: ".($!+0)
                                      "while attempting currentdump\n";      ." untie(GDBM) Failed ".
                            }      "while attempting currentdump\n";
                        } else {      }
                            print $client "error: ".($!+0)   } else {
        ." tie(GDBM) Failed ".      print $client "error: ".($!+0)
                                       "while attempting currentdump\n";   ." tie(GDBM) Failed ".
                        }   "while attempting currentdump\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
       }
 # ------------------------------------------------------------------------ dump  # ------------------------------------------------------------------------ dump
                    } elsif ($userinput =~ /^dump/) {   } elsif ($userinput =~ /^dump/) {
                        my ($cmd,$udom,$uname,$namespace,$regexp)      if(isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$uname,$namespace,$regexp)
                        $namespace=~s/\//\_/g;      =split(/:/,$userinput);
                        $namespace=~s/\W//g;   $namespace=~s/\//\_/g;
                        if (defined($regexp)) {   $namespace=~s/\W//g;
                           $regexp=&unescape($regexp);   if (defined($regexp)) {
        } else {      $regexp=&unescape($regexp);
                           $regexp='.';   } else {
        }      $regexp='.';
                        my $qresult='';   }
                        my $proname=propath($udom,$uname);   my $qresult='';
        my %hash;   my $proname=propath($udom,$uname);
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {   my %hash;
                            study($regexp);   if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                            while (my ($key,$value) = each(%hash)) {         while (my ($key,$value) = each(%hash)) {
                                if ($regexp eq '.') {     if ($regexp eq '.') {
                                    $qresult.=$key.'='.$value.'&';         $qresult.=$key.'='.$value.'&';
                                } else {     } else {
                                    my $unescapeKey = &unescape($key);         my $unescapeKey = &unescape($key);
                                    if (eval('$unescapeKey=~/$regexp/')) {         if (eval('$unescapeKey=~/$regexp/')) {
                                        $qresult.="$key=$value&";     $qresult.="$key=$value&";
                                    }         }
                                }     }
                            }         }
                            if (untie(%hash)) {         if (untie(%hash)) {
                                chop($qresult);     chop($qresult);
                                print $client "$qresult\n";     print $client "$qresult\n";
                            } else {         } else {
                                print $client "error: ".($!+0)     print $client "error: ".($!+0)
    ." untie(GDBM) Failed ".         ." untie(GDBM) Failed ".
                                        "while attempting dump\n";                                         "while attempting dump\n";
                            }         }
                        } else {     } else {
                            print $client "error: ".($!+0)         print $client "error: ".($!+0)
        ." tie(GDBM) Failed ".     ." tie(GDBM) Failed ".
                                       "while attempting dump\n";     "while attempting dump\n";
                        }     }
       } else {
    Reply($client, "refused\n", $userinput);
     
       }
 # ----------------------------------------------------------------------- store  # ----------------------------------------------------------------------- store
                    } elsif ($userinput =~ /^store/) {   } elsif ($userinput =~ /^store/) {
                       my ($cmd,$udom,$uname,$namespace,$rid,$what)      if(isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$uname,$namespace,$rid,$what)
                       $namespace=~s/\//\_/g;      =split(/:/,$userinput);
                       $namespace=~s/\W//g;   $namespace=~s/\//\_/g;
                       if ($namespace ne 'roles') {   $namespace=~s/\W//g;
                        chomp($what);   if ($namespace ne 'roles') {
                        my $proname=propath($udom,$uname);      chomp($what);
                        my $now=time;      my $proname=propath($udom,$uname);
                        unless ($namespace=~/^nohist\_/) {      my $now=time;
    my $hfh;      my @pairs=split(/\&/,$what);
    if (      my %hash;
                              $hfh=IO::File->new(">>$proname/$namespace.hist")      if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
        ) { print $hfh "P:$now:$rid:$what\n"; }   unless ($namespace=~/^nohist\_/) {
        }      my $hfh;
                        my @pairs=split(/\&/,$what);      if ($hfh=IO::File->new(">>$proname/$namespace.hist")) {
        my %hash;   print $hfh "P:$now:$rid:$what\n";
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {      }
                            my @previouskeys=split(/&/,$hash{"keys:$rid"});   }
                            my $key;   my @previouskeys=split(/&/,$hash{"keys:$rid"});
                            $hash{"version:$rid"}++;   my $key;
                            my $version=$hash{"version:$rid"};   $hash{"version:$rid"}++;
                            my $allkeys='';    my $version=$hash{"version:$rid"};
                            foreach my $pair (@pairs) {   my $allkeys=''; 
        my ($key,$value)=split(/=/,$pair);   foreach my $pair (@pairs) {
                                $allkeys.=$key.':';      my ($key,$value)=split(/=/,$pair);
                                $hash{"$version:$rid:$key"}=$value;      $allkeys.=$key.':';
                            }      $hash{"$version:$rid:$key"}=$value;
                            $hash{"$version:$rid:timestamp"}=$now;   }
                            $allkeys.='timestamp';   $hash{"$version:$rid:timestamp"}=$now;
                            $hash{"$version:keys:$rid"}=$allkeys;   $allkeys.='timestamp';
    if (untie(%hash)) {   $hash{"$version:keys:$rid"}=$allkeys;
                               print $client "ok\n";   if (untie(%hash)) {
                            } else {      print $client "ok\n";
                               print $client "error: ".($!+0)   } else {
   ." untie(GDBM) Failed ".      print $client "error: ".($!+0)
                                       "while attempting store\n";   ." untie(GDBM) Failed ".
                            }   "while attempting store\n";
                        } else {   }
                            print $client "error: ".($!+0)      } else {
        ." tie(GDBM) Failed ".   print $client "error: ".($!+0)
                                    "while attempting store\n";      ." tie(GDBM) Failed ".
                        }      "while attempting store\n";
       } else {      }
                           print $client "refused\n";   } else {
                       }      print $client "refused\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
        
       }
 # --------------------------------------------------------------------- restore  # --------------------------------------------------------------------- restore
                    } elsif ($userinput =~ /^restore/) {   } elsif ($userinput =~ /^restore/) {
                        my ($cmd,$udom,$uname,$namespace,$rid)      if(isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$uname,$namespace,$rid)
                        $namespace=~s/\//\_/g;      =split(/:/,$userinput);
                        $namespace=~s/\W//g;   $namespace=~s/\//\_/g;
                        chomp($rid);   $namespace=~s/\W//g;
                        my $proname=propath($udom,$uname);   chomp($rid);
                        my $qresult='';   my $proname=propath($udom,$uname);
        my %hash;   my $qresult='';
        if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {   my %hash;
                   my $version=$hash{"version:$rid"};   if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                            $qresult.="version=$version&";      my $version=$hash{"version:$rid"};
                            my $scope;      $qresult.="version=$version&";
                            for ($scope=1;$scope<=$version;$scope++) {      my $scope;
       my $vkeys=$hash{"$scope:keys:$rid"};      for ($scope=1;$scope<=$version;$scope++) {
                               my @keys=split(/:/,$vkeys);   my $vkeys=$hash{"$scope:keys:$rid"};
                               my $key;   my @keys=split(/:/,$vkeys);
                               $qresult.="$scope:keys=$vkeys&";   my $key;
                               foreach $key (@keys) {   $qresult.="$scope:keys=$vkeys&";
      $qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&";   foreach $key (@keys) {
                               }                                        $qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&";
                            }   }                                  
    if (untie(%hash)) {      }
               $qresult=~s/\&$//;      if (untie(%hash)) {
                               print $client "$qresult\n";   $qresult=~s/\&$//;
                            } else {   print $client "$qresult\n";
                               print $client "error: ".($!+0)      } else {
   ." untie(GDBM) Failed ".   print $client "error: ".($!+0)
                                       "while attempting restore\n";      ." untie(GDBM) Failed ".
                            }      "while attempting restore\n";
                        } else {      }
                            print $client "error: ".($!+0)   } else {
        ." tie(GDBM) Failed ".      print $client "error: ".($!+0)
                                    "while attempting restore\n";   ." tie(GDBM) Failed ".
                        }   "while attempting restore\n";
    }
       } else  {
    Reply($client, "refused\n", $userinput);
          
       }
 # -------------------------------------------------------------------- chatsend  # -------------------------------------------------------------------- chatsend
                    } elsif ($userinput =~ /^chatsend/) {   } elsif ($userinput =~ /^chatsend/) {
                        my ($cmd,$cdom,$cnum,$newpost)=split(/\:/,$userinput);      if(isClient) {
                        &chatadd($cdom,$cnum,$newpost);   my ($cmd,$cdom,$cnum,$newpost)=split(/\:/,$userinput);
                        print $client "ok\n";   &chatadd($cdom,$cnum,$newpost);
    print $client "ok\n";
       } else {
    Reply($client, "refused\n", $userinput);
         
       }
 # -------------------------------------------------------------------- chatretr  # -------------------------------------------------------------------- chatretr
                    } elsif ($userinput =~ /^chatretr/) {   } elsif ($userinput =~ /^chatretr/) {
                        my       if(isClient) {
                         ($cmd,$cdom,$cnum,$udom,$uname)=split(/\:/,$userinput);   my 
                        my $reply='';      ($cmd,$cdom,$cnum,$udom,$uname)=split(/\:/,$userinput);
                        foreach (&getchat($cdom,$cnum,$udom,$uname)) {   my $reply='';
    $reply.=&escape($_).':';   foreach (&getchat($cdom,$cnum,$udom,$uname)) {
                        }      $reply.=&escape($_).':';
                        $reply=~s/\:$//;   }
                        print $client $reply."\n";   $reply=~s/\:$//;
    print $client $reply."\n";
       } else {
    Reply($client, "refused\n", $userinput);
          
       }
 # ------------------------------------------------------------------- querysend  # ------------------------------------------------------------------- querysend
                    } elsif ($userinput =~ /^querysend/) {   } elsif ($userinput =~ /^querysend/) {
                        my ($cmd,$query,      if (isClient) {
    $arg1,$arg2,$arg3)=split(/\:/,$userinput);   my ($cmd,$query,
        $query=~s/\n*$//g;      $arg1,$arg2,$arg3)=split(/\:/,$userinput);
        print $client "".   $query=~s/\n*$//g;
        sqlreply("$hostid{$clientip}\&$query".   print $client "".
  "\&$arg1"."\&$arg2"."\&$arg3")."\n";      sqlreply("$clientname\&$query".
        "\&$arg1"."\&$arg2"."\&$arg3")."\n";
       } else {
    Reply($client, "refused\n", $userinput);
         
       }
 # ------------------------------------------------------------------ queryreply  # ------------------------------------------------------------------ queryreply
                    } elsif ($userinput =~ /^queryreply/) {   } elsif ($userinput =~ /^queryreply/) {
                        my ($cmd,$id,$reply)=split(/:/,$userinput);       if(isClient) {
        my $store;   my ($cmd,$id,$reply)=split(/:/,$userinput); 
                        my $execdir=$perlvar{'lonDaemons'};   my $store;
                        if ($store=IO::File->new(">$execdir/tmp/$id")) {   my $execdir=$perlvar{'lonDaemons'};
    $reply=~s/\&/\n/g;   if ($store=IO::File->new(">$execdir/tmp/$id")) {
    print $store $reply;      $reply=~s/\&/\n/g;
    close $store;      print $store $reply;
    my $store2=IO::File->new(">$execdir/tmp/$id.end");      close $store;
    print $store2 "done\n";      my $store2=IO::File->new(">$execdir/tmp/$id.end");
    close $store2;      print $store2 "done\n";
    print $client "ok\n";      close $store2;
        }      print $client "ok\n";
        else {   }
    print $client "error: ".($!+0)   else {
        ." IO::File->new Failed ".      print $client "error: ".($!+0)
                                    "while attempting queryreply\n";   ." IO::File->new Failed ".
        }   "while attempting queryreply\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
        
       }
 # ----------------------------------------------------------------- courseidput  # ----------------------------------------------------------------- courseidput
                    } elsif ($userinput =~ /^courseidput/) {   } elsif ($userinput =~ /^courseidput/) {
                        my ($cmd,$udom,$what)=split(/:/,$userinput);      if(isClient) {
                        chomp($what);   my ($cmd,$udom,$what)=split(/:/,$userinput);
                        $udom=~s/\W//g;   chomp($what);
                        my $proname=   $udom=~s/\W//g;
                               "$perlvar{'lonUsersDir'}/$udom/nohist_courseids";   my $proname=
                        my $now=time;      "$perlvar{'lonUsersDir'}/$udom/nohist_courseids";
                        my @pairs=split(/\&/,$what);   my $now=time;
        my %hash;   my @pairs=split(/\&/,$what);
        if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_WRCREAT(),0640)) {   my %hash;
                            foreach my $pair (@pairs) {   if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_WRCREAT(),0640)) {
        my ($key,$value)=split(/=/,$pair);      foreach my $pair (@pairs) {
                                $hash{$key}=$value.':'.$now;   my ($key,$descr,$inst_code)=split(/=/,$pair);
                            }   $hash{$key}=$descr.':'.$inst_code.':'.$now;
    if (untie(%hash)) {      }
                               print $client "ok\n";      if (untie(%hash)) {
                            } else {   print $client "ok\n";
                               print $client "error: ".($!+0)      } else {
   ." untie(GDBM) Failed ".   print $client "error: ".($!+0)
                                       "while attempting courseidput\n";      ." untie(GDBM) Failed ".
                            }      "while attempting courseidput\n";
                        } else {      }
                            print $client "error: ".($!+0)   } else {
        ." tie(GDBM) Failed ".      print $client "error: ".($!+0)
                                       "while attempting courseidput\n";   ." tie(GDBM) Failed ".
                        }   "while attempting courseidput\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
          
       }
 # ---------------------------------------------------------------- courseiddump  # ---------------------------------------------------------------- courseiddump
                    } elsif ($userinput =~ /^courseiddump/) {   } elsif ($userinput =~ /^courseiddump/) {
                        my ($cmd,$udom,$since,$description)      if(isClient) {
                           =split(/:/,$userinput);   my ($cmd,$udom,$since,$description)
                        if (defined($description)) {      =split(/:/,$userinput);
                           $description=&unescape($description);   if (defined($description)) {
        } else {      $description=&unescape($description);
                           $description='.';   } else {
        }      $description='.';
                        unless (defined($since)) { $since=0; }   }
                        my $qresult='';   unless (defined($since)) { $since=0; }
                        my $proname=   my $qresult='';
                               "$perlvar{'lonUsersDir'}/$udom/nohist_courseids";   my $proname=
        my %hash;      "$perlvar{'lonUsersDir'}/$udom/nohist_courseids";
        if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_READER(),0640)) {   my %hash;
                            while (my ($key,$value) = each(%hash)) {   if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_READER(),0640)) {
                                my ($descr,$lasttime)=split(/\:/,$value);      while (my ($key,$value) = each(%hash)) {
                                if ($lasttime<$since) { next; }                                  my ($descr,$lasttime,$inst_code);
                                if ($description eq '.') {                                  if ($value =~ m/^([^\:]*):([^\:]*):(\d+)$/) {
                                    $qresult.=$key.'='.$descr.'&';      ($descr,$inst_code,$lasttime)=($1,$2,$3);
                                } else {                                  } else {
                                    my $unescapeVal = &unescape($descr);                                      ($descr,$lasttime) = split(/\:/,$value);
                                    if (eval('$unescapeVal=~/$description/i')) {                                  }
                                        $qresult.="$key=$descr&";   if ($lasttime<$since) { next; }
                                    }   if ($description eq '.') {
                                }      $qresult.=$key.'='.$descr.':'.$inst_code.'&';
                            }   } else {
                            if (untie(%hash)) {      my $unescapeVal = &unescape($descr);
                                chop($qresult);      if (eval('$unescapeVal=~/\Q$description\E/i')) {
                                print $client "$qresult\n";   $qresult.=$key.'='.$descr.':'.$inst_code.'&';
                            } else {      }
                                print $client "error: ".($!+0)   }
    ." untie(GDBM) Failed ".      }
                                        "while attempting courseiddump\n";      if (untie(%hash)) {
                            }   chop($qresult);
                        } else {   print $client "$qresult\n";
                            print $client "error: ".($!+0)      } else {
        ." tie(GDBM) Failed ".   print $client "error: ".($!+0)
                                       "while attempting courseiddump\n";      ." untie(GDBM) Failed ".
                        }      "while attempting courseiddump\n";
       }
    } else {
       print $client "error: ".($!+0)
    ." tie(GDBM) Failed ".
    "while attempting courseiddump\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
          
       }
 # ----------------------------------------------------------------------- idput  # ----------------------------------------------------------------------- idput
                    } elsif ($userinput =~ /^idput/) {   } elsif ($userinput =~ /^idput/) {
                        my ($cmd,$udom,$what)=split(/:/,$userinput);      if(isClient) {
                        chomp($what);   my ($cmd,$udom,$what)=split(/:/,$userinput);
                        $udom=~s/\W//g;   chomp($what);
                        my $proname="$perlvar{'lonUsersDir'}/$udom/ids";   $udom=~s/\W//g;
                        my $now=time;   my $proname="$perlvar{'lonUsersDir'}/$udom/ids";
                        {   my $now=time;
    my $hfh;   my @pairs=split(/\&/,$what);
    if (   my %hash;
                              $hfh=IO::File->new(">>$proname.hist")   if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_WRCREAT(),0640)) {
        ) { print $hfh "P:$now:$what\n"; }      {
        }   my $hfh;
                        my @pairs=split(/\&/,$what);   if ($hfh=IO::File->new(">>$proname.hist")) {
        my %hash;      print $hfh "P:$now:$what\n";
        if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_WRCREAT(),0640)) {   }
                            foreach my $pair (@pairs) {      }
        my ($key,$value)=split(/=/,$pair);      foreach my $pair (@pairs) {
                                $hash{$key}=$value;   my ($key,$value)=split(/=/,$pair);
                            }   $hash{$key}=$value;
    if (untie(%hash)) {      }
                               print $client "ok\n";      if (untie(%hash)) {
                            } else {   print $client "ok\n";
                               print $client "error: ".($!+0)      } else {
   ." untie(GDBM) Failed ".   print $client "error: ".($!+0)
                                       "while attempting idput\n";      ." untie(GDBM) Failed ".
                            }      "while attempting idput\n";
                        } else {      }
                            print $client "error: ".($!+0)   } else {
        ." tie(GDBM) Failed ".      print $client "error: ".($!+0)
                                       "while attempting idput\n";   ." tie(GDBM) Failed ".
                        }   "while attempting idput\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
          
       }
 # ----------------------------------------------------------------------- idget  # ----------------------------------------------------------------------- idget
                    } elsif ($userinput =~ /^idget/) {   } elsif ($userinput =~ /^idget/) {
                        my ($cmd,$udom,$what)=split(/:/,$userinput);      if(isClient) {
                        chomp($what);   my ($cmd,$udom,$what)=split(/:/,$userinput);
                        $udom=~s/\W//g;   chomp($what);
                        my $proname="$perlvar{'lonUsersDir'}/$udom/ids";   $udom=~s/\W//g;
                        my @queries=split(/\&/,$what);   my $proname="$perlvar{'lonUsersDir'}/$udom/ids";
                        my $qresult='';   my @queries=split(/\&/,$what);
        my %hash;   my $qresult='';
        if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_READER(),0640)) {   my %hash;
                            for (my $i=0;$i<=$#queries;$i++) {   if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_READER(),0640)) {
                                $qresult.="$hash{$queries[$i]}&";      for (my $i=0;$i<=$#queries;$i++) {
                            }   $qresult.="$hash{$queries[$i]}&";
    if (untie(%hash)) {      }
        $qresult=~s/\&$//;      if (untie(%hash)) {
        print $client "$qresult\n";   $qresult=~s/\&$//;
                            } else {   print $client "$qresult\n";
        print $client "error: ".($!+0)      } else {
    ." untie(GDBM) Failed ".   print $client "error: ".($!+0)
        "while attempting idget\n";      ." untie(GDBM) Failed ".
                            }      "while attempting idget\n";
                        } else {      }
                            print $client "error: ".($!+0)   } else {
        ." tie(GDBM) Failed ".      print $client "error: ".($!+0)
                                    "while attempting idget\n";   ." tie(GDBM) Failed ".
                        }   "while attempting idget\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
          
       }
 # ---------------------------------------------------------------------- tmpput  # ---------------------------------------------------------------------- tmpput
                    } elsif ($userinput =~ /^tmpput/) {   } elsif ($userinput =~ /^tmpput/) {
                        my ($cmd,$what)=split(/:/,$userinput);      if(isClient) {
        my $store;   my ($cmd,$what)=split(/:/,$userinput);
                        $tmpsnum++;   my $store;
                        my $id=$$.'_'.$clientip.'_'.$tmpsnum;   $tmpsnum++;
                        $id=~s/\W/\_/g;   my $id=$$.'_'.$clientip.'_'.$tmpsnum;
                        $what=~s/\n//g;   $id=~s/\W/\_/g;
                        my $execdir=$perlvar{'lonDaemons'};   $what=~s/\n//g;
                        if ($store=IO::File->new(">$execdir/tmp/$id.tmp")) {   my $execdir=$perlvar{'lonDaemons'};
    print $store $what;   if ($store=IO::File->new(">$execdir/tmp/$id.tmp")) {
    close $store;      print $store $what;
    print $client "$id\n";      close $store;
        }      print $client "$id\n";
        else {   }
    print $client "error: ".($!+0)   else {
        ."IO::File->new Failed ".      print $client "error: ".($!+0)
                                    "while attempting tmpput\n";   ."IO::File->new Failed ".
        }   "while attempting tmpput\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
       
       }
       
 # ---------------------------------------------------------------------- tmpget  # ---------------------------------------------------------------------- tmpget
                    } elsif ($userinput =~ /^tmpget/) {   } elsif ($userinput =~ /^tmpget/) {
                        my ($cmd,$id)=split(/:/,$userinput);      if(isClient) {
                        chomp($id);   my ($cmd,$id)=split(/:/,$userinput);
                        $id=~s/\W/\_/g;   chomp($id);
                        my $store;   $id=~s/\W/\_/g;
                        my $execdir=$perlvar{'lonDaemons'};   my $store;
                        if ($store=IO::File->new("$execdir/tmp/$id.tmp")) {   my $execdir=$perlvar{'lonDaemons'};
                            my $reply=<$store>;   if ($store=IO::File->new("$execdir/tmp/$id.tmp")) {
    print $client "$reply\n";      my $reply=<$store>;
                            close $store;      print $client "$reply\n";
        }      close $store;
        else {   }
    print $client "error: ".($!+0)   else {
        ."IO::File->new Failed ".      print $client "error: ".($!+0)
                                    "while attempting tmpget\n";   ."IO::File->new Failed ".
        }   "while attempting tmpget\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
         
       }
 # ---------------------------------------------------------------------- tmpdel  # ---------------------------------------------------------------------- tmpdel
                    } elsif ($userinput =~ /^tmpdel/) {   } elsif ($userinput =~ /^tmpdel/) {
                        my ($cmd,$id)=split(/:/,$userinput);      if(isClient) {
                        chomp($id);   my ($cmd,$id)=split(/:/,$userinput);
                        $id=~s/\W/\_/g;   chomp($id);
                        my $execdir=$perlvar{'lonDaemons'};   $id=~s/\W/\_/g;
                        if (unlink("$execdir/tmp/$id.tmp")) {   my $execdir=$perlvar{'lonDaemons'};
    print $client "ok\n";   if (unlink("$execdir/tmp/$id.tmp")) {
        } else {      print $client "ok\n";
    print $client "error: ".($!+0)   } else {
        ."Unlink tmp Failed ".      print $client "error: ".($!+0)
                                    "while attempting tmpdel\n";   ."Unlink tmp Failed ".
        }   "while attempting tmpdel\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
        
       }
   # ----------------------------------------- portfolio directory list (portls)
                   } elsif ($userinput =~ /^portls/) {
                       if(isClient) {
                           my ($cmd,$uname,$udom)=split(/:/,$userinput);
                           my $udir=propath($udom,$uname).'/userfiles/portfolio';
                           my $dirLine='';
                           my $dirContents='';
                           if (opendir(LSDIR,$udir.'/')){
                               while ($dirLine = readdir(LSDIR)){
                                   $dirContents = $dirContents.$dirLine.'<br />';
                               }
                           } else {
                               $dirContents = "No directory found\n";
                           }
                           print $client $dirContents."\n";
                       } else {
                           Reply($client, "refused\n", $userinput);
                       }
 # -------------------------------------------------------------------------- ls  # -------------------------------------------------------------------------- ls
                    } elsif ($userinput =~ /^ls/) {   } elsif ($userinput =~ /^ls/) {
                        my ($cmd,$ulsdir)=split(/:/,$userinput);      if(isClient) {
                        my $ulsout='';   my $obs;
                        my $ulsfn;   my $rights;
                        if (-e $ulsdir) {   my ($cmd,$ulsdir)=split(/:/,$userinput);
                            if(-d $ulsdir) {   my $ulsout='';
                                if (opendir(LSDIR,$ulsdir)) {   my $ulsfn;
                                    while ($ulsfn=readdir(LSDIR)) {   if (-e $ulsdir) {
                                        my @ulsstats=stat($ulsdir.'/'.$ulsfn);      if(-d $ulsdir) {
                                        $ulsout.=$ulsfn.'&'.   if (opendir(LSDIR,$ulsdir)) {
                                                 join('&',@ulsstats).':';      while ($ulsfn=readdir(LSDIR)) {
                                    }   undef $obs, $rights; 
                                    closedir(LSDIR);   my @ulsstats=stat($ulsdir.'/'.$ulsfn);
                                }   #We do some obsolete checking here
                            } else {   if(-e $ulsdir.'/'.$ulsfn.".meta") { 
                                my @ulsstats=stat($ulsdir);      open(FILE, $ulsdir.'/'.$ulsfn.".meta");
                                $ulsout.=$ulsfn.'&'.join('&',@ulsstats).':';      my @obsolete=<FILE>;
                            }      foreach my $obsolete (@obsolete) {
                        } else {          if($obsolete =~ m|(<obsolete>)(on)|) { $obs = 1; } 
                           $ulsout='no_such_dir';   if($obsolete =~ m|(<copyright>)(default)|) { $rights = 1; }
                        }      }
                        if ($ulsout eq '') { $ulsout='empty'; }   }
                        print $client "$ulsout\n";   $ulsout.=$ulsfn.'&'.join('&',@ulsstats);
    if($obs eq '1') { $ulsout.="&1"; }
    else { $ulsout.="&0"; }
    if($rights eq '1') { $ulsout.="&1:"; }
    else { $ulsout.="&0:"; }
       }
       closedir(LSDIR);
    }
       } else {
    my @ulsstats=stat($ulsdir);
    $ulsout.=$ulsfn.'&'.join('&',@ulsstats).':';
       }
    } else {
       $ulsout='no_such_dir';
    }
    if ($ulsout eq '') { $ulsout='empty'; }
    print $client "$ulsout\n";
       } else {
    Reply($client, "refused\n", $userinput);
        
       }
 # ----------------------------------------------------------------- setannounce  # ----------------------------------------------------------------- setannounce
                    } elsif ($userinput =~ /^setannounce/) {   } elsif ($userinput =~ /^setannounce/) {
        my ($cmd,$announcement)=split(/:/,$userinput);      if (isClient) {
        chomp($announcement);   my ($cmd,$announcement)=split(/:/,$userinput);
        $announcement=&unescape($announcement);   chomp($announcement);
                        if (my $store=IO::File->new('>'.$perlvar{'lonDocRoot'}.   $announcement=&unescape($announcement);
  '/announcement.txt')) {   if (my $store=IO::File->new('>'.$perlvar{'lonDocRoot'}.
    print $store $announcement;      '/announcement.txt')) {
                            close $store;      print $store $announcement;
    print $client "ok\n";      close $store;
        } else {      print $client "ok\n";
    print $client "error: ".($!+0)."\n";   } else {
        }      print $client "error: ".($!+0)."\n";
    }
       } else {
    Reply($client, "refused\n", $userinput);
          
       }
 # ------------------------------------------------------------------ Hanging up  # ------------------------------------------------------------------ Hanging up
                    } elsif (($userinput =~ /^exit/) ||   } elsif (($userinput =~ /^exit/) ||
                             ($userinput =~ /^init/)) {   ($userinput =~ /^init/)) { # no restrictions.
                        &logthis(      &logthis(
       "Client $clientip ($hostid{$clientip}) hanging up: $userinput");       "Client $clientip ($clientname) hanging up: $userinput");
                        print $client "bye\n";      print $client "bye\n";
                        $client->close();      $client->shutdown(2);        # shutdown the socket forcibly.
        last;      $client->close();
       last;
   
   # ---------------------------------- set current host/domain
    } elsif ($userinput =~ /^sethost:/) {
       if (isClient) {
    print $client &sethost($userinput)."\n";
       } else {
    print $client "refused\n";
       }
   #---------------------------------- request file (?) version.
    } elsif ($userinput =~/^version:/) {
       if (isClient) {
    print $client &version($userinput)."\n";
       } else {
    print $client "refused\n";
       }
   #------------------------------- is auto-enrollment enabled?
                   } elsif ($userinput =~/^autorun:/) {
                       if (isClient) {
                           my ($cmd,$cdom) = split(/:/,$userinput);
                           my $outcome = &localenroll::run($cdom);
                           print $client "$outcome\n";
                       } else {
                           print $client "0\n";
                       }
   #------------------------------- get official sections (for auto-enrollment).
                   } elsif ($userinput =~/^autogetsections:/) {
                       if (isClient) {
                           my ($cmd,$coursecode,$cdom)=split(/:/,$userinput);
                           my @secs = &localenroll::get_sections($coursecode,$cdom);
                           my $seclist = &escape(join(':',@secs));
                           print $client "$seclist\n";
                       } else {
                           print $client "refused\n";
                       }
   #----------------------- validate owner of new course section (for auto-enrollment).
                   } elsif ($userinput =~/^autonewcourse:/) {
                       if (isClient) {
                           my ($cmd,$inst_course_id,$owner,$cdom)=split(/:/,$userinput);
                           my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom);
                           print $client "$outcome\n";
                       } else {
                           print $client "refused\n";
                       }
   #-------------- validate course section in schedule of classes (for auto-enrollment).
                   } elsif ($userinput =~/^autovalidatecourse:/) {
                       if (isClient) {
                           my ($cmd,$inst_course_id,$cdom)=split(/:/,$userinput);
                           my $outcome=&localenroll::validate_courseID($inst_course_id,$cdom);
                           print $client "$outcome\n";
                       } else {
                           print $client "refused\n";
                       }
   #--------------------------- create password for new user (for auto-enrollment).
                   } elsif ($userinput =~/^autocreatepassword:/) {
                       if (isClient) {
                           my ($cmd,$authparam,$cdom)=split(/:/,$userinput);
                           my ($create_passwd,$authchk);
                           ($authparam,$create_passwd,$authchk) = &localenroll::create_password($authparam,$cdom);
                           print $client &escape($authparam.':'.$create_passwd.':'.$authchk)."\n";
                       } else {
                           print $client "refused\n";
                       }
   #---------------------------  read and remove temporary files (for auto-enrollment).
                   } elsif ($userinput =~/^autoretrieve:/) {
                       if (isClient) {
                           my ($cmd,$filename) = split(/:/,$userinput);
                           my $source = $perlvar{'lonDaemons'}.'/tmp/'.$filename;
                           if ( (-e $source) && ($filename ne '') ) {
                               my $reply = '';
                               if (open(my $fh,$source)) {
                                   while (<$fh>) {
                                       chomp($_);
                                       $_ =~ s/^\s+//g;
                                       $_ =~ s/\s+$//g;
                                       $reply .= $_;
                                   }
                                   close($fh);
                                   print $client &escape($reply)."\n";
   #                                unlink($source);
                               } else {
                                   print $client "error\n";
                               }
                           } else {
                               print $client "error\n";
                           }
                       } else {
                           print $client "refused\n";
                       }
   #---------------------  read and retrieve institutional code format (for support form).
                   } elsif ($userinput =~/^autoinstcodeformat:/) {
                       if (isClient) {
                           my $reply;
                           my($cmd,$cdom,$course) = split(/:/,$userinput);
                           my @pairs = split/\&/,$course;
                           my %instcodes = ();
                           my %codes = ();
                           my @codetitles = ();
                           my %cat_titles = ();
                           my %cat_order = ();
                           foreach (@pairs) {
                               my ($key,$value) = split/=/,$_;
                               $instcodes{&unescape($key)} = &unescape($value);
                           }
                           my $formatreply = &localenroll::instcode_format($cdom,\%instcodes,\%codes,\@codetitles,\%cat_titles,\%cat_order);
                           if ($formatreply eq 'ok') {
                               my $codes_str = &hash2str(%codes);
                               my $codetitles_str = &array2str(@codetitles);
                               my $cat_titles_str = &hash2str(%cat_titles);
                               my $cat_order_str = &hash2str(%cat_order);
                               print $client $codes_str.':'.$codetitles_str.':'.$cat_titles_str.':'.$cat_order_str."\n";
                           }
                       } else {
                           print $client "refused\n";
                       }
 # ------------------------------------------------------------- unknown command  # ------------------------------------------------------------- unknown command
    } elsif ($userinput =~ /^sethost:/) {  
        print $client &sethost($userinput)."\n";   } else {
    } elsif ($userinput =~/^version:/) {      # unknown command
        print $client &version($userinput)."\n";      print $client "unknown_cmd\n";
                    } else {   }
                        # unknown command  
                        print $client "unknown_cmd\n";  
                    }  
 # -------------------------------------------------------------------- complete  # -------------------------------------------------------------------- complete
    alarm(0);   alarm(0);
                    &status('Listening to '.$hostid{$clientip});   &status('Listening to '.$clientname." ($keymode)");
        }      }
 # --------------------------------------------- client unknown or fishy, refuse  # --------------------------------------------- client unknown or fishy, refuse
             } else {   } else {
         print $client "refused\n";      print $client "refused\n";
                 $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: "      &logthis("<font color='red'>CRITICAL: "
  ."Disconnect from $clientip ($hostid{$clientip})</font>");           ."Disconnect from $clientip ($clientname)</font>");    
       
       
         # this exit is VERY important, otherwise the child will become      # this exit is VERY important, otherwise the child will become
         # a producer of more and more children, forking yourself into      # a producer of more and more children, forking yourself into
         # process death.      # process death.
         exit;      exit;
           
 }  }
   
Line 2240  sub make_new_child { Line 3522  sub make_new_child {
 #  #
 sub ManagePermissions  sub ManagePermissions
 {  {
     my $request = shift;  
     my $domain  = shift;      my ($request, $domain, $user, $authtype) = @_;
     my $user    = shift;  
     my $authtype= shift;  
   
     # See if the request is of the form /$domain/_au      # See if the request is of the form /$domain/_au
     &logthis("ruequest is $request");  
     if($request =~ /^(\/$domain\/_au)$/) { # It's an author rolesput...      if($request =~ /^(\/$domain\/_au)$/) { # It's an author rolesput...
  my $execdir = $perlvar{'lonDaemons'};   my $execdir = $perlvar{'lonDaemons'};
  my $userhome= "/home/$user" ;   my $userhome= "/home/$user" ;
Line 2261  sub ManagePermissions Line 3540  sub ManagePermissions
 #  #
 sub GetAuthType   sub GetAuthType 
 {  {
     my $domain = shift;  
     my $user   = shift;      my ($domain, $user)  = @_;
   
     Debug("GetAuthType( $domain, $user ) \n");      Debug("GetAuthType( $domain, $user ) \n");
     my $proname    = &propath($domain, $user);       my $proname    = &propath($domain, $user); 
Line 2371  sub chatadd { Line 3650  sub chatadd {
 sub unsub {  sub unsub {
     my ($fname,$clientip)=@_;      my ($fname,$clientip)=@_;
     my $result;      my $result;
     if (unlink("$fname.$hostid{$clientip}")) {      my $unsubs = 0; # Number of successful unsubscribes:
  $result="ok\n";  
     } else {  
  $result="not_subscribed\n";      # An old way subscriptions were handled was to have a 
     }      # subscription marker file:
   
       Debug("Attempting unlink of $fname.$clientname");
       if (unlink("$fname.$clientname")) {
    $unsubs++; # Successful unsub via marker file.
       } 
   
       # The more modern way to do it is to have a subscription list
       # file:
   
     if (-e "$fname.subscription") {      if (-e "$fname.subscription") {
  my $found=&addline($fname,$hostid{$clientip},$clientip,'');   my $found=&addline($fname,$clientname,$clientip,'');
  if ($found) { $result="ok\n"; }   if ($found) { 
       $unsubs++;
    }
       } 
   
       #  If either or both of these mechanisms succeeded in unsubscribing a 
       #  resource we can return ok:
   
       if($unsubs) {
    $result = "ok\n";
     } else {      } else {
  if ($result != "ok\n") { $result="not_subscribed\n"; }   $result = "not_subscribed\n";
     }      }
   
     return $result;      return $result;
 }  }
   
Line 2409  sub currentversion { Line 3707  sub currentversion {
 # see if this is a regular file (ignore links produced earlier)  # see if this is a regular file (ignore links produced earlier)
     my $thisfile=$ulsdir.'/'.$ulsfn;      my $thisfile=$ulsdir.'/'.$ulsfn;
     unless (-l $thisfile) {      unless (-l $thisfile) {
  if ($thisfile=~/\Q$fnamere1\E(\d+)\Q$fnamere2\E/) {   if ($thisfile=~/\Q$fnamere1\E(\d+)\Q$fnamere2\E$/) {
     if ($1>$version) { $version=$1; }      if ($1>$version) { $version=$1; }
  }   }
     }      }
Line 2457  sub subscribe { Line 3755  sub subscribe {
     if (-d $fname) {      if (-d $fname) {
  $result="directory\n";   $result="directory\n";
     } else {      } else {
  if (-e "$fname.$hostid{$clientip}") {&unsub($fname,$clientip);}   if (-e "$fname.$clientname") {&unsub($fname,$clientip);}
  my $now=time;   my $now=time;
  my $found=&addline($fname,$hostid{$clientip},$clientip,   my $found=&addline($fname,$clientname,$clientip,
    "$hostid{$clientip}:$clientip:$now\n");     "$clientname:$clientip:$now\n");
  if ($found) { $result="$fname\n"; }   if ($found) { $result="$fname\n"; }
  # if they were subscribed to only meta data, delete that   # if they were subscribed to only meta data, delete that
                 # subscription, when you subscribe to a file you also get                  # subscription, when you subscribe to a file you also get
Line 2503  sub make_passwd_file { Line 3801  sub make_passwd_file {
  }   }
     } elsif ($umode eq 'unix') {      } elsif ($umode eq 'unix') {
  {   {
       #
       #  Don't allow the creation of privileged accounts!!! that would
       #  be real bad!!!
       #
       my $uid = getpwnam($uname);
       if((defined $uid) && ($uid == 0)) {
    &logthis(">>>Attempted to create privilged account blocked");
    return "no_priv_account_error\n";
       }
   
     my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd";      my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd";
     {      {
  &Debug("Executing external: ".$execpath);   &Debug("Executing external: ".$execpath);
Line 2535  sub sethost { Line 3843  sub sethost {
     my (undef,$hostid)=split(/:/,$remotereq);      my (undef,$hostid)=split(/:/,$remotereq);
     if (!defined($hostid)) { $hostid=$perlvar{'lonHostID'}; }      if (!defined($hostid)) { $hostid=$perlvar{'lonHostID'}; }
     if ($hostip{$perlvar{'lonHostID'}} eq $hostip{$hostid}) {      if ($hostip{$perlvar{'lonHostID'}} eq $hostip{$hostid}) {
  $currenthostid=$hostid;   $currenthostid  =$hostid;
  $currentdomainid=$hostdom{$hostid};   $currentdomainid=$hostdom{$hostid};
  &logthis("Setting hostid to $hostid, and domain to $currentdomainid");   &logthis("Setting hostid to $hostid, and domain to $currentdomainid");
     } else {      } else {
Line 2562  sub userload { Line 3870  sub userload {
  while ($filename=readdir(LONIDS)) {   while ($filename=readdir(LONIDS)) {
     if ($filename eq '.' || $filename eq '..') {next;}      if ($filename eq '.' || $filename eq '..') {next;}
     my ($mtime)=(stat($perlvar{'lonIDsDir'}.'/'.$filename))[9];      my ($mtime)=(stat($perlvar{'lonIDsDir'}.'/'.$filename))[9];
     if ($curtime-$mtime < 3600) { $numusers++; }      if ($curtime-$mtime < 1800) { $numusers++; }
  }   }
  closedir(LONIDS);   closedir(LONIDS);
     }      }
Line 2575  sub userload { Line 3883  sub userload {
     return $userloadpercent;      return $userloadpercent;
 }  }
   
   # Routines for serializing arrays and hashes (copies from lonnet)
   
   sub array2str {
     my (@array) = @_;
     my $result=&arrayref2str(\@array);
     $result=~s/^__ARRAY_REF__//;
     $result=~s/__END_ARRAY_REF__$//;
     return $result;
   }
                                                                                    
   sub arrayref2str {
     my ($arrayref) = @_;
     my $result='__ARRAY_REF__';
     foreach my $elem (@$arrayref) {
       if(ref($elem) eq 'ARRAY') {
         $result.=&arrayref2str($elem).'&';
       } elsif(ref($elem) eq 'HASH') {
         $result.=&hashref2str($elem).'&';
       } elsif(ref($elem)) {
         #print("Got a ref of ".(ref($elem))." skipping.");
       } else {
         $result.=&escape($elem).'&';
       }
     }
     $result=~s/\&$//;
     $result .= '__END_ARRAY_REF__';
     return $result;
   }
                                                                                    
   sub hash2str {
     my (%hash) = @_;
     my $result=&hashref2str(\%hash);
     $result=~s/^__HASH_REF__//;
     $result=~s/__END_HASH_REF__$//;
     return $result;
   }
                                                                                    
   sub hashref2str {
     my ($hashref)=@_;
     my $result='__HASH_REF__';
     foreach (sort(keys(%$hashref))) {
       if (ref($_) eq 'ARRAY') {
         $result.=&arrayref2str($_).'=';
       } elsif (ref($_) eq 'HASH') {
         $result.=&hashref2str($_).'=';
       } elsif (ref($_)) {
         $result.='=';
         #print("Got a ref of ".(ref($_))." skipping.");
       } else {
           if ($_) {$result.=&escape($_).'=';} else { last; }
       }
   
       if(ref($hashref->{$_}) eq 'ARRAY') {
         $result.=&arrayref2str($hashref->{$_}).'&';
       } elsif(ref($hashref->{$_}) eq 'HASH') {
         $result.=&hashref2str($hashref->{$_}).'&';
       } elsif(ref($hashref->{$_})) {
          $result.='&';
         #print("Got a ref of ".(ref($hashref->{$_}))." skipping.");
       } else {
         $result.=&escape($hashref->{$_}).'&';
       }
     }
     $result=~s/\&$//;
     $result .= '__END_HASH_REF__';
     return $result;
   }
   
 # ----------------------------------- POD (plain old documentation, CPAN style)  # ----------------------------------- POD (plain old documentation, CPAN style)
   
 =head1 NAME  =head1 NAME

Removed from v.1.153  
changed lines
  Added in v.1.211


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