Annotation of loncom/lond, revision 1.165.2.4

1.1       albertel    1: #!/usr/bin/perl
                      2: # The LearningOnline Network
                      3: # lond "LON Daemon" Server (port "LOND" 5663)
1.60      www         4: #
1.165.2.4! albertel    5: # $Id: lond,v 1.165.2.3 2004/03/08 20:13:07 albertel Exp $
1.60      www         6: #
                      7: # Copyright Michigan State University Board of Trustees
                      8: #
                      9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                     10: #
                     11: # LON-CAPA is free software; you can redistribute it and/or modify
                     12: # it under the terms of the GNU General Public License as published by
                     13: # the Free Software Foundation; either version 2 of the License, or
                     14: # (at your option) any later version.
                     15: #
                     16: # LON-CAPA is distributed in the hope that it will be useful,
                     17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     19: # GNU General Public License for more details.
                     20: #
                     21: # You should have received a copy of the GNU General Public License
                     22: # along with LON-CAPA; if not, write to the Free Software
                     23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     24: #
                     25: # /home/httpd/html/adm/gpl.txt
                     26: #
1.161     foxr       27: 
                     28: 
1.60      www        29: # http://www.lon-capa.org/
                     30: #
1.54      harris41   31: 
1.134     albertel   32: use strict;
1.80      harris41   33: use lib '/home/httpd/lib/perl/';
                     34: use LONCAPA::Configuration;
                     35: 
1.1       albertel   36: use IO::Socket;
                     37: use IO::File;
1.126     albertel   38: #use Apache::File;
1.1       albertel   39: use Symbol;
                     40: use POSIX;
                     41: use Crypt::IDEA;
                     42: use LWP::UserAgent();
1.3       www        43: use GDBM_File;
                     44: use Authen::Krb4;
1.91      albertel   45: use Authen::Krb5;
1.49      albertel   46: use lib '/home/httpd/lib/perl/';
                     47: use localauth;
1.143     foxr       48: use File::Copy;
1.1       albertel   49: 
1.77      foxr       50: my $DEBUG = 0;		       # Non zero to enable debug log entries.
                     51: 
1.57      www        52: my $status='';
                     53: my $lastlog='';
                     54: 
1.165.2.4! albertel   55: my $VERSION='$Revision: 1.165.2.3 $'; #' stupid emacs
1.121     albertel   56: my $remoteVERSION;
1.115     albertel   57: my $currenthostid;
                     58: my $currentdomainid;
1.134     albertel   59: 
                     60: my $client;
1.140     foxr       61: my $clientip;
1.161     foxr       62: my $clientname;
1.140     foxr       63: 
1.134     albertel   64: my $server;
                     65: my $thisserver;
                     66: 
1.161     foxr       67: # 
                     68: #   Connection type is:
                     69: #      client                   - All client actions are allowed
                     70: #      manager                  - only management functions allowed.
                     71: #      both                     - Both management and client actions are allowed
                     72: #
                     73: 
                     74: my $ConnectionType;
                     75: 
1.134     albertel   76: my %hostid;
                     77: my %hostdom;
                     78: my %hostip;
1.161     foxr       79: 
                     80: my %managers;			# Ip -> manager names
                     81: 
1.141     foxr       82: my %perlvar;			# Will have the apache conf defined perl vars.
1.134     albertel   83: 
1.96      foxr       84: #
                     85: #  The array below are password error strings."
                     86: #
1.97      foxr       87: my $lastpwderror    = 13;		# Largest error number from lcpasswd.
1.96      foxr       88: my @passwderrors = ("ok",
                     89: 		   "lcpasswd must be run as user 'www'",
                     90: 		   "lcpasswd got incorrect number of arguments",
                     91: 		   "lcpasswd did not get the right nubmer of input text lines",
                     92: 		   "lcpasswd too many simultaneous pwd changes in progress",
                     93: 		   "lcpasswd User does not exist.",
                     94: 		   "lcpasswd Incorrect current passwd",
                     95: 		   "lcpasswd Unable to su to root.",
                     96: 		   "lcpasswd Cannot set new passwd.",
                     97: 		   "lcpasswd Username has invalid characters",
1.97      foxr       98: 		   "lcpasswd Invalid characters in password",
                     99: 		    "11", "12",
                    100: 		    "lcpasswd Password mismatch");
                    101: 
                    102: 
                    103: #  The array below are lcuseradd error strings.:
                    104: 
                    105: my $lastadderror = 13;
                    106: my @adderrors    = ("ok",
                    107: 		    "User ID mismatch, lcuseradd must run as user www",
                    108: 		    "lcuseradd Incorrect number of command line parameters must be 3",
                    109: 		    "lcuseradd Incorrect number of stdinput lines, must be 3",
                    110: 		    "lcuseradd Too many other simultaneous pwd changes in progress",
                    111: 		    "lcuseradd User does not exist",
1.153     www       112: 		    "lcuseradd Unable to make www member of users's group",
1.97      foxr      113: 		    "lcuseradd Unable to su to root",
                    114: 		    "lcuseradd Unable to set password",
1.153     www       115: 		    "lcuseradd Usrname has invalid characters",
1.97      foxr      116: 		    "lcuseradd Password has an invalid character",
                    117: 		    "lcuseradd User already exists",
                    118: 		    "lcuseradd Could not add user.",
                    119: 		    "lcuseradd Password mismatch");
                    120: 
1.96      foxr      121: 
                    122: #
1.140     foxr      123: #   GetCertificate: Given a transaction that requires a certificate,
                    124: #   this function will extract the certificate from the transaction
                    125: #   request.  Note that at this point, the only concept of a certificate
                    126: #   is the hostname to which we are connected.
                    127: #
                    128: #   Parameter:
                    129: #      request   - The request sent by our client (this parameterization may
                    130: #                  need to change when we really use a certificate granting
                    131: #                  authority.
                    132: #
                    133: sub GetCertificate {
                    134:     my $request = shift;
                    135: 
                    136:     return $clientip;
                    137: }
1.161     foxr      138: 
                    139: #
                    140: #   Return true if client is a manager.
                    141: #
                    142: sub isManager {
                    143:     return (($ConnectionType eq "manager") || ($ConnectionType eq "both"));
                    144: }
                    145: #
                    146: #   Return tru if client can do client functions
                    147: #
                    148: sub isClient {
                    149:     return (($ConnectionType eq "client") || ($ConnectionType eq "both"));
                    150: }
                    151: 
                    152: 
1.156     foxr      153: #
                    154: #   ReadManagerTable: Reads in the current manager table. For now this is
                    155: #                     done on each manager authentication because:
                    156: #                     - These authentications are not frequent
                    157: #                     - This allows dynamic changes to the manager table
                    158: #                       without the need to signal to the lond.
                    159: #
                    160: 
                    161: sub ReadManagerTable {
                    162: 
                    163:     #   Clean out the old table first..
                    164: 
                    165:     foreach my $key (keys %managers) {
                    166: 	delete $managers{$key};
                    167:     }
                    168: 
                    169:     my $tablename = $perlvar{'lonTabDir'}."/managers.tab";
                    170:     if (!open (MANAGERS, $tablename)) {
                    171: 	logthis('<font color="red">No manager table.  Nobody can manage!!</font>');
                    172: 	return;
                    173:     }
                    174:     while(my $host = <MANAGERS>) {
                    175: 	chomp($host);
1.161     foxr      176: 	if (!defined $hostip{$host}) { # This is a non cluster member
                    177: 
                    178: 	    #  The entry is of the form:
                    179: 	    #    cluname:hostname
                    180: 	    #  cluname - A 'cluster hostname' is needed in order to negotiate
                    181: 	    #            the host key.
                    182: 	    #  hostname- The dns name of the host.
                    183: 	    #
                    184: 	    
                    185: 	    my($cluname, $dnsname) = split(/:/, $host);
                    186: 	    open(MGRPIPE, "/usr/bin/host $dnsname |") || die "Can't make host pipeline";
                    187: 	    my $dnsinfo = <MGRPIPE>;
                    188: 	    chomp $dnsinfo;
                    189: 	    close MGRPIPE;
                    190: 	    my($jname, $jhas, $jaddress, $hostip) = split(/ /, $dnsinfo);
                    191: 	    $managers{$hostip} = $cluname;
1.156     foxr      192: 	} else {
1.161     foxr      193: 	    $managers{$hostip{$host}} = $host;  # Use info from cluster tab if clumemeber
1.156     foxr      194: 	}
                    195:     }
                    196: }
1.140     foxr      197: 
                    198: #
                    199: #  ValidManager: Determines if a given certificate represents a valid manager.
                    200: #                in this primitive implementation, the 'certificate' is
                    201: #                just the connecting loncapa client name.  This is checked
                    202: #                against a valid client list in the configuration.
                    203: #
                    204: #                  
                    205: sub ValidManager {
                    206:     my $certificate = shift; 
                    207: 
1.163     foxr      208:     return isManager;
1.140     foxr      209: }
                    210: #
1.143     foxr      211: #  CopyFile:  Called as part of the process of installing a 
                    212: #             new configuration file.  This function copies an existing
                    213: #             file to a backup file.
                    214: # Parameters:
                    215: #     oldfile  - Name of the file to backup.
                    216: #     newfile  - Name of the backup file.
                    217: # Return:
                    218: #     0   - Failure (errno has failure reason).
                    219: #     1   - Success.
                    220: #
                    221: sub CopyFile {
                    222:     my $oldfile = shift;
                    223:     my $newfile = shift;
                    224: 
                    225:     #  The file must exist:
                    226: 
                    227:     if(-e $oldfile) {
                    228: 
                    229: 	 # Read the old file.
                    230: 
                    231: 	my $oldfh = IO::File->new("< $oldfile");
                    232: 	if(!$oldfh) {
                    233: 	    return 0;
                    234: 	}
                    235: 	my @contents = <$oldfh>;  # Suck in the entire file.
                    236: 
                    237: 	# write the backup file:
                    238: 
                    239: 	my $newfh = IO::File->new("> $newfile");
                    240: 	if(!(defined $newfh)){
                    241: 	    return 0;
                    242: 	}
                    243: 	my $lines = scalar @contents;
                    244: 	for (my $i =0; $i < $lines; $i++) {
                    245: 	    print $newfh ($contents[$i]);
                    246: 	}
                    247: 
                    248: 	$oldfh->close;
                    249: 	$newfh->close;
                    250: 
                    251: 	chmod(0660, $newfile);
                    252: 
                    253: 	return 1;
                    254: 	    
                    255:     } else {
                    256: 	return 0;
                    257:     }
                    258: }
1.157     foxr      259: #
                    260: #  Host files are passed out with externally visible host IPs.
                    261: #  If, for example, we are behind a fire-wall or NAT host, our 
                    262: #  internally visible IP may be different than the externally
                    263: #  visible IP.  Therefore, we always adjust the contents of the
                    264: #  host file so that the entry for ME is the IP that we believe
                    265: #  we have.  At present, this is defined as the entry that
                    266: #  DNS has for us.  If by some chance we are not able to get a
                    267: #  DNS translation for us, then we assume that the host.tab file
                    268: #  is correct.  
                    269: #    BUGBUGBUG - in the future, we really should see if we can
                    270: #       easily query the interface(s) instead.
                    271: # Parameter(s):
                    272: #     contents    - The contents of the host.tab to check.
                    273: # Returns:
                    274: #     newcontents - The adjusted contents.
                    275: #
                    276: #
                    277: sub AdjustHostContents {
                    278:     my $contents  = shift;
                    279:     my $adjusted;
                    280:     my $me        = $perlvar{'lonHostID'};
                    281: 
                    282:     foreach my $line (split(/\n/,$contents)) {
                    283: 	if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/))) {
                    284: 	    chomp($line);
                    285: 	    my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon)=split(/:/,$line);
                    286: 	    if ($id eq $me) {
                    287: 		open(PIPE, " /usr/bin/host $name |") || die "Cant' make host pipeline";
                    288: 		my $hostinfo = <PIPE>;
                    289: 		close PIPE;
                    290: 		
                    291: 		my ($hostname, $has, $address, $ipnew) = split(/ /,$hostinfo);
                    292: 		&logthis('<font color="green">'.
                    293: 			 "hostname = $hostname me = $me, name = $name   actual ip = $ipnew </font>");
                    294: 		
                    295: 		if ($hostname eq $name) { # Lookup succeeded..
                    296: 		    &logthis('<font color="green"> look up ok <font>');
                    297: 		    $ip = $ipnew;
                    298: 		} else {
                    299: 		    &logthis('<font color="green"> Lookup failed: '
                    300: 			     .$hostname." ne $name </font>");
                    301: 		}
                    302: 		#  Reconstruct the host line and append to adjusted:
                    303: 		
                    304: 		my $newline = "$id:$domain:$role:$name:$ip";
                    305: 		if($maxcon ne "") { # Not all hosts have loncnew tuning params
                    306: 		    $newline .= ":$maxcon:$idleto:$mincon";
                    307: 		}
                    308: 		$adjusted .= $newline."\n";
                    309: 		
                    310: 	    } else {		# Not me, pass unmodified.
                    311: 		$adjusted .= $line."\n";
                    312: 	    }
                    313: 	} else {                  # Blank or comment never re-written.
                    314: 	    $adjusted .= $line."\n";	# Pass blanks and comments as is.
                    315: 	}
                    316:     }
                    317:     return $adjusted;
                    318: }
1.143     foxr      319: #
                    320: #   InstallFile: Called to install an administrative file:
                    321: #       - The file is created with <name>.tmp
                    322: #       - The <name>.tmp file is then mv'd to <name>
                    323: #   This lugubrious procedure is done to ensure that we are never without
                    324: #   a valid, even if dated, version of the file regardless of who crashes
                    325: #   and when the crash occurs.
                    326: #
                    327: #  Parameters:
                    328: #       Name of the file
                    329: #       File Contents.
                    330: #  Return:
                    331: #      nonzero - success.
                    332: #      0       - failure and $! has an errno.
                    333: #
                    334: sub InstallFile {
                    335:     my $Filename = shift;
                    336:     my $Contents = shift;
                    337:     my $TempFile = $Filename.".tmp";
                    338: 
                    339:     #  Open the file for write:
                    340: 
                    341:     my $fh = IO::File->new("> $TempFile"); # Write to temp.
                    342:     if(!(defined $fh)) {
                    343: 	&logthis('<font color="red"> Unable to create '.$TempFile."</font>");
                    344: 	return 0;
                    345:     }
                    346:     #  write the contents of the file:
                    347: 
                    348:     print $fh ($Contents); 
                    349:     $fh->close;			# In case we ever have a filesystem w. locking
                    350: 
                    351:     chmod(0660, $TempFile);
                    352: 
                    353:     # Now we can move install the file in position.
                    354:     
                    355:     move($TempFile, $Filename);
                    356: 
                    357:     return 1;
                    358: }
                    359: 
                    360: #
1.141     foxr      361: #   PushFile:  Called to do an administrative push of a file.
                    362: #              - Ensure the file being pushed is one we support.
                    363: #              - Backup the old file to <filename.saved>
                    364: #              - Separate the contents of the new file out from the
                    365: #                rest of the request.
                    366: #              - Write the new file.
                    367: #  Parameter:
                    368: #     Request - The entire user request.  This consists of a : separated
                    369: #               string pushfile:tablename:contents.
                    370: #     NOTE:  The contents may have :'s in it as well making things a bit
                    371: #            more interesting... but not much.
                    372: #  Returns:
                    373: #     String to send to client ("ok" or "refused" if bad file).
                    374: #
                    375: sub PushFile {
                    376:     my $request = shift;    
                    377:     my ($command, $filename, $contents) = split(":", $request, 3);
                    378:     
                    379:     #  At this point in time, pushes for only the following tables are
                    380:     #  supported:
                    381:     #   hosts.tab  ($filename eq host).
                    382:     #   domain.tab ($filename eq domain).
                    383:     # Construct the destination filename or reject the request.
                    384:     #
                    385:     # lonManage is supposed to ensure this, however this session could be
                    386:     # part of some elaborate spoof that managed somehow to authenticate.
                    387:     #
                    388: 
                    389:     my $tablefile = $perlvar{'lonTabDir'}.'/'; # need to precede with dir.
                    390:     if ($filename eq "host") {
                    391: 	$tablefile .= "hosts.tab";
                    392:     } elsif ($filename eq "domain") {
                    393: 	$tablefile .= "domain.tab";
                    394:     } else {
                    395: 	return "refused";
                    396:     }
                    397:     #
                    398:     # >copy< the old table to the backup table
                    399:     #        don't rename in case system crashes/reboots etc. in the time
                    400:     #        window between a rename and write.
                    401:     #
                    402:     my $backupfile = $tablefile;
                    403:     $backupfile    =~ s/\.tab$/.old/;
1.143     foxr      404:     if(!CopyFile($tablefile, $backupfile)) {
                    405: 	&logthis('<font color="green"> CopyFile from '.$tablefile." to ".$backupfile." failed </font>");
                    406: 	return "error:$!";
                    407:     }
1.141     foxr      408:     &logthis('<font color="green"> Pushfile: backed up '
                    409: 	    .$tablefile." to $backupfile</font>");
                    410:     
1.157     foxr      411:     #  If the file being pushed is the host file, we adjust the entry for ourself so that the
                    412:     #  IP will be our current IP as looked up in dns.  Note this is only 99% good as it's possible
                    413:     #  to conceive of conditions where we don't have a DNS entry locally.  This is possible in a 
                    414:     #  network sense but it doesn't make much sense in a LonCAPA sense so we ignore (for now)
                    415:     #  that possibilty.
                    416: 
                    417:     if($filename eq "host") {
                    418: 	$contents = AdjustHostContents($contents);
                    419:     }
                    420: 
1.141     foxr      421:     #  Install the new file:
                    422: 
1.143     foxr      423:     if(!InstallFile($tablefile, $contents)) {
                    424: 	&logthis('<font color="red"> Pushfile: unable to install '
1.145     foxr      425: 	 .$tablefile." $! </font>");
1.143     foxr      426: 	return "error:$!";
                    427:     }
                    428:     else {
                    429: 	&logthis('<font color="green"> Installed new '.$tablefile
                    430: 		 ."</font>");
                    431: 
                    432:     }
                    433: 
1.141     foxr      434: 
                    435:     #  Indicate success:
                    436:  
                    437:     return "ok";
                    438: 
                    439: }
1.145     foxr      440: 
                    441: #
                    442: #  Called to re-init either lonc or lond.
                    443: #
                    444: #  Parameters:
                    445: #    request   - The full request by the client.  This is of the form
                    446: #                reinit:<process>  
                    447: #                where <process> is allowed to be either of 
                    448: #                lonc or lond
                    449: #
                    450: #  Returns:
                    451: #     The string to be sent back to the client either:
                    452: #   ok         - Everything worked just fine.
                    453: #   error:why  - There was a failure and why describes the reason.
                    454: #
                    455: #
                    456: sub ReinitProcess {
                    457:     my $request = shift;
                    458: 
1.146     foxr      459: 
                    460:     # separate the request (reinit) from the process identifier and
                    461:     # validate it producing the name of the .pid file for the process.
                    462:     #
                    463:     #
                    464:     my ($junk, $process) = split(":", $request);
1.147     foxr      465:     my $processpidfile = $perlvar{'lonDaemons'}.'/logs/';
1.146     foxr      466:     if($process eq 'lonc') {
                    467: 	$processpidfile = $processpidfile."lonc.pid";
1.147     foxr      468: 	if (!open(PIDFILE, "< $processpidfile")) {
                    469: 	    return "error:Open failed for $processpidfile";
                    470: 	}
                    471: 	my $loncpid = <PIDFILE>;
                    472: 	close(PIDFILE);
                    473: 	logthis('<font color="red"> Reinitializing lonc pid='.$loncpid
                    474: 		."</font>");
                    475: 	kill("USR2", $loncpid);
1.146     foxr      476:     } elsif ($process eq 'lond') {
1.147     foxr      477: 	logthis('<font color="red"> Reinitializing self (lond) </font>');
                    478: 	&UpdateHosts;			# Lond is us!!
1.146     foxr      479:     } else {
                    480: 	&logthis('<font color="yellow" Invalid reinit request for '.$process
                    481: 		 ."</font>");
                    482: 	return "error:Invalid process identifier $process";
                    483:     }
1.145     foxr      484:     return 'ok';
                    485: }
                    486: 
1.141     foxr      487: #
1.96      foxr      488: #  Convert an error return code from lcpasswd to a string value.
                    489: #
                    490: sub lcpasswdstrerror {
                    491:     my $ErrorCode = shift;
1.97      foxr      492:     if(($ErrorCode < 0) || ($ErrorCode > $lastpwderror)) {
1.96      foxr      493: 	return "lcpasswd Unrecognized error return value ".$ErrorCode;
                    494:     } else {
1.98      foxr      495: 	return $passwderrors[$ErrorCode];
1.96      foxr      496:     }
                    497: }
                    498: 
1.97      foxr      499: #
                    500: # Convert an error return code from lcuseradd to a string value:
                    501: #
                    502: sub lcuseraddstrerror {
                    503:     my $ErrorCode = shift;
                    504:     if(($ErrorCode < 0) || ($ErrorCode > $lastadderror)) {
                    505: 	return "lcuseradd - Unrecognized error code: ".$ErrorCode;
                    506:     } else {
1.98      foxr      507: 	return $adderrors[$ErrorCode];
1.97      foxr      508:     }
                    509: }
                    510: 
1.23      harris41  511: # grabs exception and records it to log before exiting
                    512: sub catchexception {
1.27      albertel  513:     my ($error)=@_;
1.25      www       514:     $SIG{'QUIT'}='DEFAULT';
                    515:     $SIG{__DIE__}='DEFAULT';
1.165     albertel  516:     &status("Catching exception");
1.23      harris41  517:     &logthis("<font color=red>CRITICAL: "
1.134     albertel  518:      ."ABNORMAL EXIT. Child $$ for server $thisserver died through "
1.27      albertel  519:      ."a crash with this error msg->[$error]</font>");
1.57      www       520:     &logthis('Famous last words: '.$status.' - '.$lastlog);
1.27      albertel  521:     if ($client) { print $client "error: $error\n"; }
1.59      www       522:     $server->close();
1.27      albertel  523:     die($error);
1.23      harris41  524: }
                    525: 
1.63      www       526: sub timeout {
1.165     albertel  527:     &status("Handling Timeout");
1.63      www       528:     &logthis("<font color=ref>CRITICAL: TIME OUT ".$$."</font>");
                    529:     &catchexception('Timeout');
                    530: }
1.22      harris41  531: # -------------------------------- Set signal handlers to record abnormal exits
                    532: 
                    533: $SIG{'QUIT'}=\&catchexception;
                    534: $SIG{__DIE__}=\&catchexception;
                    535: 
1.81      matthew   536: # ---------------------------------- Read loncapa_apache.conf and loncapa.conf
1.95      harris41  537: &status("Read loncapa.conf and loncapa_apache.conf");
                    538: my $perlvarref=LONCAPA::Configuration::read_conf('loncapa.conf');
1.141     foxr      539: %perlvar=%{$perlvarref};
1.80      harris41  540: undef $perlvarref;
1.19      www       541: 
1.35      harris41  542: # ----------------------------- Make sure this process is running from user=www
                    543: my $wwwid=getpwnam('www');
                    544: if ($wwwid!=$<) {
1.134     albertel  545:    my $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
                    546:    my $subj="LON: $currenthostid User ID mismatch";
1.37      harris41  547:    system("echo 'User ID mismatch.  lond must be run as user www.' |\
1.35      harris41  548:  mailto $emailto -s '$subj' > /dev/null");
                    549:    exit 1;
                    550: }
                    551: 
1.19      www       552: # --------------------------------------------- Check if other instance running
                    553: 
                    554: my $pidfile="$perlvar{'lonDaemons'}/logs/lond.pid";
                    555: 
                    556: if (-e $pidfile) {
                    557:    my $lfh=IO::File->new("$pidfile");
                    558:    my $pide=<$lfh>;
                    559:    chomp($pide);
1.29      harris41  560:    if (kill 0 => $pide) { die "already running"; }
1.19      www       561: }
1.1       albertel  562: 
                    563: # ------------------------------------------------------------- Read hosts file
                    564: 
                    565: 
                    566: 
                    567: # establish SERVER socket, bind and listen.
                    568: $server = IO::Socket::INET->new(LocalPort => $perlvar{'londPort'},
                    569:                                 Type      => SOCK_STREAM,
                    570:                                 Proto     => 'tcp',
                    571:                                 Reuse     => 1,
                    572:                                 Listen    => 10 )
1.29      harris41  573:   or die "making socket: $@\n";
1.1       albertel  574: 
                    575: # --------------------------------------------------------- Do global variables
                    576: 
                    577: # global variables
                    578: 
1.134     albertel  579: my %children               = ();       # keys are current child process IDs
1.1       albertel  580: 
                    581: sub REAPER {                        # takes care of dead children
                    582:     $SIG{CHLD} = \&REAPER;
1.165     albertel  583:     &status("Handling child death");
1.165.2.3  albertel  584:     my $pid;
                    585:     do {
                    586: 	$pid = waitpid(-1,&WNOHANG());
                    587: 	if (defined($children{$pid})) {
                    588: 	    &logthis("Child $pid died");
                    589: 	    delete($children{$pid});
                    590: 	} else {
                    591: 	    &logthis("Unknown Child $pid died");
                    592: 	}
                    593:     } while ( $pid > 0 );
                    594:     foreach my $child (keys(%children)) {
                    595: 	$pid = waitpid($child,&WNOHANG());
                    596: 	if ($pid > 0) {
                    597: 	    &logthis("Child $child - $pid looks like we missed it's death");
                    598: 	    delete($children{$pid});
                    599: 	}
1.67      albertel  600:     }
1.165     albertel  601:     &status("Finished Handling child death");
1.1       albertel  602: }
                    603: 
                    604: sub HUNTSMAN {                      # signal handler for SIGINT
1.165     albertel  605:     &status("Killing children (INT)");
1.1       albertel  606:     local($SIG{CHLD}) = 'IGNORE';   # we're going to kill our children
                    607:     kill 'INT' => keys %children;
1.59      www       608:     &logthis("Free socket: ".shutdown($server,2)); # free up socket
1.1       albertel  609:     my $execdir=$perlvar{'lonDaemons'};
                    610:     unlink("$execdir/logs/lond.pid");
1.9       www       611:     &logthis("<font color=red>CRITICAL: Shutting down</font>");
1.165     albertel  612:     &status("Done killing children");
1.1       albertel  613:     exit;                           # clean up with dignity
                    614: }
                    615: 
                    616: sub HUPSMAN {                      # signal handler for SIGHUP
                    617:     local($SIG{CHLD}) = 'IGNORE';  # we're going to kill our children
1.165     albertel  618:     &status("Killing children for restart (HUP)");
1.1       albertel  619:     kill 'INT' => keys %children;
1.59      www       620:     &logthis("Free socket: ".shutdown($server,2)); # free up socket
1.9       www       621:     &logthis("<font color=red>CRITICAL: Restarting</font>");
1.134     albertel  622:     my $execdir=$perlvar{'lonDaemons'};
1.30      harris41  623:     unlink("$execdir/logs/lond.pid");
1.165     albertel  624:     &status("Restarting self (HUP)");
1.1       albertel  625:     exec("$execdir/lond");         # here we go again
                    626: }
                    627: 
1.144     foxr      628: #
1.148     foxr      629: #    Kill off hashes that describe the host table prior to re-reading it.
                    630: #    Hashes affected are:
                    631: #       %hostid, %hostdom %hostip
                    632: #
                    633: sub KillHostHashes {
                    634:     foreach my $key (keys %hostid) {
                    635: 	delete $hostid{$key};
                    636:     }
                    637:     foreach my $key (keys %hostdom) {
                    638: 	delete $hostdom{$key};
                    639:     }
                    640:     foreach my $key (keys %hostip) {
                    641: 	delete $hostip{$key};
                    642:     }
                    643: }
                    644: #
                    645: #   Read in the host table from file and distribute it into the various hashes:
                    646: #
                    647: #    - %hostid  -  Indexed by IP, the loncapa hostname.
                    648: #    - %hostdom -  Indexed by  loncapa hostname, the domain.
                    649: #    - %hostip  -  Indexed by hostid, the Ip address of the host.
                    650: sub ReadHostTable {
                    651: 
                    652:     open (CONFIG,"$perlvar{'lonTabDir'}/hosts.tab") || die "Can't read host file";
                    653:     
                    654:     while (my $configline=<CONFIG>) {
1.165.2.3  albertel  655: 	if (!($configline =~ /^\s*\#/)) {
                    656: 	    my ($id,$domain,$role,$name,$ip)=split(/:/,$configline);
                    657: 	    chomp($ip); $ip=~s/\D+$//;
                    658: 	    $hostid{$ip}=$id;
                    659: 	    $hostdom{$id}=$domain;
                    660: 	    $hostip{$id}=$ip;
                    661: 	    if ($id eq $perlvar{'lonHostID'}) { $thisserver=$name; }
                    662: 	}
1.148     foxr      663:     }
                    664:     close(CONFIG);
                    665: }
                    666: #
                    667: #  Reload the Apache daemon's state.
1.150     foxr      668: #  This is done by invoking /home/httpd/perl/apachereload
                    669: #  a setuid perl script that can be root for us to do this job.
1.148     foxr      670: #
                    671: sub ReloadApache {
1.150     foxr      672:     my $execdir = $perlvar{'lonDaemons'};
                    673:     my $script  = $execdir."/apachereload";
                    674:     system($script);
1.148     foxr      675: }
                    676: 
                    677: #
1.144     foxr      678: #   Called in response to a USR2 signal.
                    679: #   - Reread hosts.tab
                    680: #   - All children connected to hosts that were removed from hosts.tab
                    681: #     are killed via SIGINT
                    682: #   - All children connected to previously existing hosts are sent SIGUSR1
                    683: #   - Our internal hosts hash is updated to reflect the new contents of
                    684: #     hosts.tab causing connections from hosts added to hosts.tab to
                    685: #     now be honored.
                    686: #
                    687: sub UpdateHosts {
1.165     albertel  688:     &status("Reload hosts.tab");
1.147     foxr      689:     logthis('<font color="blue"> Updating connections </font>');
1.148     foxr      690:     #
                    691:     #  The %children hash has the set of IP's we currently have children
                    692:     #  on.  These need to be matched against records in the hosts.tab
                    693:     #  Any ip's no longer in the table get killed off they correspond to
                    694:     #  either dropped or changed hosts.  Note that the re-read of the table
                    695:     #  will take care of new and changed hosts as connections come into being.
                    696: 
                    697: 
                    698:     KillHostHashes;
                    699:     ReadHostTable;
                    700: 
                    701:     foreach my $child (keys %children) {
                    702: 	my $childip = $children{$child};
                    703: 	if(!$hostid{$childip}) {
1.149     foxr      704: 	    logthis('<font color="blue"> UpdateHosts killing child '
                    705: 		    ." $child for ip $childip </font>");
1.148     foxr      706: 	    kill('INT', $child);
1.149     foxr      707: 	} else {
                    708: 	    logthis('<font color="green"> keeping child for ip '
                    709: 		    ." $childip (pid=$child) </font>");
1.148     foxr      710: 	}
                    711:     }
                    712:     ReloadApache;
1.165     albertel  713:     &status("Finished reloading hosts.tab");
1.144     foxr      714: }
                    715: 
1.148     foxr      716: 
1.57      www       717: sub checkchildren {
1.165     albertel  718:     &status("Checking on the children (sending signals)");
1.57      www       719:     &initnewstatus();
                    720:     &logstatus();
                    721:     &logthis('Going to check on the children');
1.134     albertel  722:     my $docdir=$perlvar{'lonDocRoot'};
1.61      harris41  723:     foreach (sort keys %children) {
1.57      www       724: 	sleep 1;
                    725:         unless (kill 'USR1' => $_) {
                    726: 	    &logthis ('Child '.$_.' is dead');
                    727:             &logstatus($$.' is dead');
                    728:         } 
1.61      harris41  729:     }
1.63      www       730:     sleep 5;
1.113     albertel  731:     $SIG{ALRM} = sub { die "timeout" };
                    732:     $SIG{__DIE__} = 'DEFAULT';
1.165     albertel  733:     &status("Checking on the children (waiting for reports)");
1.63      www       734:     foreach (sort keys %children) {
                    735:         unless (-e "$docdir/lon-status/londchld/$_.txt") {
1.113     albertel  736:           eval {
                    737:             alarm(300);
1.63      www       738: 	    &logthis('Child '.$_.' did not respond');
1.67      albertel  739: 	    kill 9 => $_;
1.131     albertel  740: 	    #$emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
                    741: 	    #$subj="LON: $currenthostid killed lond process $_";
                    742: 	    #my $result=`echo 'Killed lond process $_.' | mailto $emailto -s '$subj' > /dev/null`;
                    743: 	    #$execdir=$perlvar{'lonDaemons'};
                    744: 	    #$result=`/bin/cp $execdir/logs/lond.log $execdir/logs/lond.log.$_`;
1.113     albertel  745: 	    alarm(0);
                    746: 	  }
1.63      www       747:         }
                    748:     }
1.113     albertel  749:     $SIG{ALRM} = 'DEFAULT';
1.155     albertel  750:     $SIG{__DIE__} = \&catchexception;
1.165     albertel  751:     &status("Finished checking children");
1.57      www       752: }
                    753: 
1.1       albertel  754: # --------------------------------------------------------------------- Logging
                    755: 
                    756: sub logthis {
                    757:     my $message=shift;
                    758:     my $execdir=$perlvar{'lonDaemons'};
                    759:     my $fh=IO::File->new(">>$execdir/logs/lond.log");
                    760:     my $now=time;
                    761:     my $local=localtime($now);
1.58      www       762:     $lastlog=$local.': '.$message;
1.1       albertel  763:     print $fh "$local ($$): $message\n";
                    764: }
                    765: 
1.77      foxr      766: # ------------------------- Conditional log if $DEBUG true.
                    767: sub Debug {
                    768:     my $message = shift;
                    769:     if($DEBUG) {
                    770: 	&logthis($message);
                    771:     }
                    772: }
1.161     foxr      773: 
                    774: #
                    775: #   Sub to do replies to client.. this gives a hook for some
                    776: #   debug tracing too:
                    777: #  Parameters:
                    778: #     fd      - File open on client.
                    779: #     reply   - Text to send to client.
                    780: #     request - Original request from client.
                    781: #
                    782: sub Reply {
                    783:     my $fd      = shift;
                    784:     my $reply   = shift;
                    785:     my $request = shift;
                    786: 
                    787:     print $fd $reply;
                    788:     Debug("Request was $request  Reply was $reply");
                    789: 
                    790: }
1.57      www       791: # ------------------------------------------------------------------ Log status
                    792: 
                    793: sub logstatus {
1.165     albertel  794:     &status("Doing logging");
1.57      www       795:     my $docdir=$perlvar{'lonDocRoot'};
1.63      www       796:     {
1.57      www       797:     my $fh=IO::File->new(">>$docdir/lon-status/londstatus.txt");
1.165.2.3  albertel  798:     print $fh $$."\t".$clientname."\t".$currenthostid."\t".$status."\t".$lastlog."\n";
1.63      www       799:     $fh->close();
                    800:     }
1.165     albertel  801:     &status("Finished londstatus.txt");
1.63      www       802:     {
                    803: 	my $fh=IO::File->new(">$docdir/lon-status/londchld/$$.txt");
                    804:         print $fh $status."\n".$lastlog."\n".time;
                    805:         $fh->close();
                    806:     }
1.165     albertel  807:     &status("Finished logging");
1.57      www       808: }
                    809: 
                    810: sub initnewstatus {
                    811:     my $docdir=$perlvar{'lonDocRoot'};
                    812:     my $fh=IO::File->new(">$docdir/lon-status/londstatus.txt");
                    813:     my $now=time;
                    814:     my $local=localtime($now);
                    815:     print $fh "LOND status $local - parent $$\n\n";
1.64      www       816:     opendir(DIR,"$docdir/lon-status/londchld");
1.134     albertel  817:     while (my $filename=readdir(DIR)) {
1.64      www       818:         unlink("$docdir/lon-status/londchld/$filename");
                    819:     }
                    820:     closedir(DIR);
1.57      www       821: }
                    822: 
                    823: # -------------------------------------------------------------- Status setting
                    824: 
                    825: sub status {
                    826:     my $what=shift;
                    827:     my $now=time;
                    828:     my $local=localtime($now);
                    829:     $status=$local.': '.$what;
1.103     www       830:     $0='lond: '.$what.' '.$local;
1.57      www       831: }
1.11      www       832: 
                    833: # -------------------------------------------------------- Escape Special Chars
                    834: 
                    835: sub escape {
                    836:     my $str=shift;
                    837:     $str =~ s/(\W)/"%".unpack('H2',$1)/eg;
                    838:     return $str;
                    839: }
                    840: 
                    841: # ----------------------------------------------------- Un-Escape Special Chars
                    842: 
                    843: sub unescape {
                    844:     my $str=shift;
                    845:     $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
                    846:     return $str;
                    847: }
                    848: 
1.1       albertel  849: # ----------------------------------------------------------- Send USR1 to lonc
                    850: 
                    851: sub reconlonc {
                    852:     my $peerfile=shift;
                    853:     &logthis("Trying to reconnect for $peerfile");
                    854:     my $loncfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
                    855:     if (my $fh=IO::File->new("$loncfile")) {
                    856: 	my $loncpid=<$fh>;
                    857:         chomp($loncpid);
                    858:         if (kill 0 => $loncpid) {
                    859: 	    &logthis("lonc at pid $loncpid responding, sending USR1");
                    860:             kill USR1 => $loncpid;
                    861:         } else {
1.9       www       862: 	    &logthis(
                    863:               "<font color=red>CRITICAL: "
                    864:              ."lonc at pid $loncpid not responding, giving up</font>");
1.1       albertel  865:         }
                    866:     } else {
1.9       www       867:       &logthis('<font color=red>CRITICAL: lonc not running, giving up</font>');
1.1       albertel  868:     }
                    869: }
                    870: 
                    871: # -------------------------------------------------- Non-critical communication
1.11      www       872: 
1.1       albertel  873: sub subreply {
                    874:     my ($cmd,$server)=@_;
                    875:     my $peerfile="$perlvar{'lonSockDir'}/$server";
                    876:     my $sclient=IO::Socket::UNIX->new(Peer    =>"$peerfile",
                    877:                                       Type    => SOCK_STREAM,
                    878:                                       Timeout => 10)
                    879:        or return "con_lost";
                    880:     print $sclient "$cmd\n";
                    881:     my $answer=<$sclient>;
                    882:     chomp($answer);
                    883:     if (!$answer) { $answer="con_lost"; }
                    884:     return $answer;
                    885: }
                    886: 
                    887: sub reply {
                    888:   my ($cmd,$server)=@_;
                    889:   my $answer;
1.115     albertel  890:   if ($server ne $currenthostid) { 
1.1       albertel  891:     $answer=subreply($cmd,$server);
                    892:     if ($answer eq 'con_lost') {
                    893: 	$answer=subreply("ping",$server);
                    894:         if ($answer ne $server) {
1.115     albertel  895: 	    &logthis("sub reply: answer != server answer is $answer, server is $server");
1.1       albertel  896:            &reconlonc("$perlvar{'lonSockDir'}/$server");
                    897:         }
                    898:         $answer=subreply($cmd,$server);
                    899:     }
                    900:   } else {
                    901:     $answer='self_reply';
                    902:   } 
                    903:   return $answer;
                    904: }
                    905: 
1.13      www       906: # -------------------------------------------------------------- Talk to lonsql
                    907: 
1.12      harris41  908: sub sqlreply {
                    909:     my ($cmd)=@_;
                    910:     my $answer=subsqlreply($cmd);
                    911:     if ($answer eq 'con_lost') { $answer=subsqlreply($cmd); }
                    912:     return $answer;
                    913: }
                    914: 
                    915: sub subsqlreply {
                    916:     my ($cmd)=@_;
                    917:     my $unixsock="mysqlsock";
                    918:     my $peerfile="$perlvar{'lonSockDir'}/$unixsock";
                    919:     my $sclient=IO::Socket::UNIX->new(Peer    =>"$peerfile",
                    920:                                       Type    => SOCK_STREAM,
                    921:                                       Timeout => 10)
                    922:        or return "con_lost";
                    923:     print $sclient "$cmd\n";
                    924:     my $answer=<$sclient>;
                    925:     chomp($answer);
                    926:     if (!$answer) { $answer="con_lost"; }
                    927:     return $answer;
                    928: }
                    929: 
1.1       albertel  930: # -------------------------------------------- Return path to profile directory
1.11      www       931: 
1.1       albertel  932: sub propath {
                    933:     my ($udom,$uname)=@_;
                    934:     $udom=~s/\W//g;
                    935:     $uname=~s/\W//g;
1.16      www       936:     my $subdir=$uname.'__';
1.1       albertel  937:     $subdir =~ s/(.)(.)(.).*/$1\/$2\/$3/;
                    938:     my $proname="$perlvar{'lonUsersDir'}/$udom/$subdir/$uname";
                    939:     return $proname;
                    940: } 
                    941: 
                    942: # --------------------------------------- Is this the home server of an author?
1.11      www       943: 
1.1       albertel  944: sub ishome {
                    945:     my $author=shift;
                    946:     $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;
                    947:     my ($udom,$uname)=split(/\//,$author);
                    948:     my $proname=propath($udom,$uname);
                    949:     if (-e $proname) {
                    950: 	return 'owner';
                    951:     } else {
                    952:         return 'not_owner';
                    953:     }
                    954: }
                    955: 
                    956: # ======================================================= Continue main program
                    957: # ---------------------------------------------------- Fork once and dissociate
                    958: 
1.134     albertel  959: my $fpid=fork;
1.1       albertel  960: exit if $fpid;
1.29      harris41  961: die "Couldn't fork: $!" unless defined ($fpid);
1.1       albertel  962: 
1.29      harris41  963: POSIX::setsid() or die "Can't start new session: $!";
1.1       albertel  964: 
                    965: # ------------------------------------------------------- Write our PID on disk
                    966: 
1.134     albertel  967: my $execdir=$perlvar{'lonDaemons'};
1.1       albertel  968: open (PIDSAVE,">$execdir/logs/lond.pid");
                    969: print PIDSAVE "$$\n";
                    970: close(PIDSAVE);
1.9       www       971: &logthis("<font color=red>CRITICAL: ---------- Starting ----------</font>");
1.57      www       972: &status('Starting');
1.1       albertel  973: 
1.106     foxr      974: 
1.1       albertel  975: 
                    976: # ----------------------------------------------------- Install signal handlers
                    977: 
1.57      www       978: 
1.1       albertel  979: $SIG{CHLD} = \&REAPER;
                    980: $SIG{INT}  = $SIG{TERM} = \&HUNTSMAN;
                    981: $SIG{HUP}  = \&HUPSMAN;
1.57      www       982: $SIG{USR1} = \&checkchildren;
1.144     foxr      983: $SIG{USR2} = \&UpdateHosts;
1.106     foxr      984: 
1.148     foxr      985: #  Read the host hashes:
                    986: 
                    987: ReadHostTable;
1.106     foxr      988: 
                    989: # --------------------------------------------------------------
                    990: #   Accept connections.  When a connection comes in, it is validated
                    991: #   and if good, a child process is created to process transactions
                    992: #   along the connection.
                    993: 
1.1       albertel  994: while (1) {
1.165     albertel  995:     &status('Starting accept');
1.106     foxr      996:     $client = $server->accept() or next;
1.165     albertel  997:     &status('Accepted '.$client.' off to spawn');
1.106     foxr      998:     make_new_child($client);
1.165     albertel  999:     &status('Finished spawning');
1.1       albertel 1000: }
                   1001: 
                   1002: sub make_new_child {
                   1003:     my $pid;
                   1004:     my $cipher;
                   1005:     my $sigset;
1.106     foxr     1006: 
                   1007:     $client = shift;
1.165     albertel 1008:     &status('Starting new child '.$client);
1.161     foxr     1009:     &logthis('<font color="green"> Attempting to start child ('.$client.
                   1010: 	     ")</font>");    
1.1       albertel 1011:     # block signal for fork
                   1012:     $sigset = POSIX::SigSet->new(SIGINT);
                   1013:     sigprocmask(SIG_BLOCK, $sigset)
1.29      harris41 1014:         or die "Can't block SIGINT for fork: $!\n";
1.134     albertel 1015: 
1.29      harris41 1016:     die "fork: $!" unless defined ($pid = fork);
1.148     foxr     1017: 
                   1018:     $client->sockopt(SO_KEEPALIVE, 1); # Enable monitoring of
                   1019: 	                               # connection liveness.
                   1020: 
                   1021:     #
                   1022:     #  Figure out who we're talking to so we can record the peer in 
                   1023:     #  the pid hash.
                   1024:     #
                   1025:     my $caller = getpeername($client);
                   1026:     my ($port,$iaddr)=unpack_sockaddr_in($caller);
                   1027:     $clientip=inet_ntoa($iaddr);
1.1       albertel 1028:     
                   1029:     if ($pid) {
                   1030:         # Parent records the child's birth and returns.
                   1031:         sigprocmask(SIG_UNBLOCK, $sigset)
1.29      harris41 1032:             or die "Can't unblock SIGINT for fork: $!\n";
1.148     foxr     1033:         $children{$pid} = $clientip;
1.57      www      1034:         &status('Started child '.$pid);
1.1       albertel 1035:         return;
                   1036:     } else {
                   1037:         # Child can *not* return from this subroutine.
                   1038:         $SIG{INT} = 'DEFAULT';      # make SIGINT kill us as it did before
1.126     albertel 1039:         $SIG{CHLD} = 'DEFAULT'; #make this default so that pwauth returns 
                   1040:                                 #don't get intercepted
1.57      www      1041:         $SIG{USR1}= \&logstatus;
1.63      www      1042:         $SIG{ALRM}= \&timeout;
1.57      www      1043:         $lastlog='Forked ';
                   1044:         $status='Forked';
                   1045: 
1.1       albertel 1046:         # unblock signals
                   1047:         sigprocmask(SIG_UNBLOCK, $sigset)
1.29      harris41 1048:             or die "Can't unblock SIGINT for fork: $!\n";
1.13      www      1049: 
1.134     albertel 1050:         my $tmpsnum=0;
1.91      albertel 1051: #---------------------------------------------------- kerberos 5 initialization
                   1052:         &Authen::Krb5::init_context();
                   1053:         &Authen::Krb5::init_ets();
                   1054: 
1.161     foxr     1055: 	&status('Accepted connection');
1.1       albertel 1056: # =============================================================================
                   1057:             # do something with the connection
                   1058: # -----------------------------------------------------------------------------
1.148     foxr     1059: 	# see if we know client and check for spoof IP by challenge
                   1060: 
1.161     foxr     1061: 	ReadManagerTable;	# May also be a manager!!
                   1062: 	
                   1063: 	my $clientrec=($hostid{$clientip}     ne undef);
                   1064: 	my $ismanager=($managers{$clientip}    ne undef);
                   1065: 	$clientname  = "[unknonwn]";
                   1066: 	if($clientrec) {	# Establish client type.
                   1067: 	    $ConnectionType = "client";
                   1068: 	    $clientname = $hostid{$clientip};
                   1069: 	    if($ismanager) {
                   1070: 		$ConnectionType = "both";
                   1071: 	    }
                   1072: 	} else {
                   1073: 	    $ConnectionType = "manager";
                   1074: 	    $clientname = $managers{$clientip};
                   1075: 	}
                   1076: 	my $clientok;
                   1077: 	if ($clientrec || $ismanager) {
                   1078: 	    &status("Waiting for init from $clientip $clientname");
                   1079: 	    &logthis('<font color="yellow">INFO: Connection, '.
                   1080: 		     $clientip.
                   1081: 		  " ($clientname) connection type = $ConnectionType </font>" );
                   1082: 	    &status("Connecting $clientip  ($clientname))"); 
                   1083: 	    my $remotereq=<$client>;
                   1084: 	    $remotereq=~s/[^\w:]//g;
                   1085: 	    if ($remotereq =~ /^init/) {
                   1086: 		&sethost("sethost:$perlvar{'lonHostID'}");
                   1087: 		my $challenge="$$".time;
                   1088: 		print $client "$challenge\n";
                   1089: 		&status(
                   1090: 			"Waiting for challenge reply from $clientip ($clientname)"); 
                   1091: 		$remotereq=<$client>;
                   1092: 		$remotereq=~s/\W//g;
                   1093: 		if ($challenge eq $remotereq) {
                   1094: 		    $clientok=1;
                   1095: 		    print $client "ok\n";
                   1096: 		} else {
                   1097: 		    &logthis(
                   1098: 			     "<font color=blue>WARNING: $clientip did not reply challenge</font>");
                   1099: 		    &status('No challenge reply '.$clientip);
                   1100: 		}
1.2       www      1101: 	    } else {
1.161     foxr     1102: 		&logthis(
                   1103: 			 "<font color=blue>WARNING: "
                   1104: 			 ."$clientip failed to initialize: >$remotereq< </font>");
                   1105: 		&status('No init '.$clientip);
                   1106: 	    }
                   1107: 	} else {
                   1108: 	    &logthis(
                   1109: 		     "<font color=blue>WARNING: Unknown client $clientip</font>");
                   1110: 	    &status('Hung up on '.$clientip);
                   1111: 	}
                   1112: 	if ($clientok) {
1.1       albertel 1113: # ---------------- New known client connecting, could mean machine online again
1.161     foxr     1114: 	    
                   1115: 	    foreach my $id (keys(%hostip)) {
                   1116: 		if ($hostip{$id} ne $clientip ||
                   1117: 		    $hostip{$currenthostid} eq $clientip) {
                   1118: 		    # no need to try to do recon's to myself
                   1119: 		    next;
1.115     albertel 1120: 		}
1.161     foxr     1121: 		&reconlonc("$perlvar{'lonSockDir'}/$id");
                   1122: 	    }
                   1123: 	    &logthis("<font color=green>Established connection: $clientname</font>");
                   1124: 	    &status('Will listen to '.$clientname);
1.1       albertel 1125: # ------------------------------------------------------------ Process requests
1.161     foxr     1126: 	    while (my $userinput=<$client>) {
1.1       albertel 1127:                 chomp($userinput);
1.79      foxr     1128: 		Debug("Request = $userinput\n");
1.161     foxr     1129:                 &status('Processing '.$clientname.': '.$userinput);
1.1       albertel 1130:                 my $wasenc=0;
1.63      www      1131:                 alarm(120);
1.1       albertel 1132: # ------------------------------------------------------------ See if encrypted
                   1133: 		if ($userinput =~ /^enc/) {
1.161     foxr     1134: 		    if ($cipher) {
                   1135: 			my ($cmd,$cmdlength,$encinput)=split(/:/,$userinput);
                   1136: 			$userinput='';
                   1137: 			for (my $encidx=0;$encidx<length($encinput);$encidx+=16) {
                   1138: 			    $userinput.=
                   1139: 				$cipher->decrypt(
                   1140: 						 pack("H16",substr($encinput,$encidx,16))
                   1141: 						 );
                   1142: 			}
                   1143: 			$userinput=substr($userinput,0,$cmdlength);
                   1144: 			$wasenc=1;
1.1       albertel 1145: 		    }
                   1146: 		}
1.161     foxr     1147: 		
1.1       albertel 1148: # ------------------------------------------------------------- Normal commands
                   1149: # ------------------------------------------------------------------------ ping
1.161     foxr     1150: 		if ($userinput =~ /^ping/) {	# client only
                   1151: 		    if(isClient) {
                   1152: 			print $client "$currenthostid\n";
                   1153: 		    } else {
                   1154: 			Reply($client, "refused\n", $userinput);
                   1155: 		    }
1.1       albertel 1156: # ------------------------------------------------------------------------ pong
1.161     foxr     1157: 		}elsif ($userinput =~ /^pong/) { # client only
                   1158: 		    if(isClient) {
                   1159: 			my $reply=&reply("ping",$clientname);
                   1160: 			print $client "$currenthostid:$reply\n"; 
                   1161: 		    } else {
                   1162: 			Reply($client, "refused\n", $userinput);
                   1163: 		    }
1.1       albertel 1164: # ------------------------------------------------------------------------ ekey
1.161     foxr     1165: 		} elsif ($userinput =~ /^ekey/) { # ok for both clients & mgrs
                   1166: 		    my $buildkey=time.$$.int(rand 100000);
                   1167: 		    $buildkey=~tr/1-6/A-F/;
                   1168: 		    $buildkey=int(rand 100000).$buildkey.int(rand 100000);
                   1169: 		    my $key=$currenthostid.$clientname;
                   1170: 		    $key=~tr/a-z/A-Z/;
                   1171: 		    $key=~tr/G-P/0-9/;
                   1172: 		    $key=~tr/Q-Z/0-9/;
                   1173: 		    $key=$key.$buildkey.$key.$buildkey.$key.$buildkey;
                   1174: 		    $key=substr($key,0,32);
                   1175: 		    my $cipherkey=pack("H32",$key);
                   1176: 		    $cipher=new IDEA $cipherkey;
                   1177: 		    print $client "$buildkey\n"; 
1.1       albertel 1178: # ------------------------------------------------------------------------ load
1.161     foxr     1179: 		} elsif ($userinput =~ /^load/) { # client only
                   1180: 		    if (isClient) {
                   1181: 			my $loadavg;
                   1182: 			{
                   1183: 			    my $loadfile=IO::File->new('/proc/loadavg');
                   1184: 			    $loadavg=<$loadfile>;
                   1185: 			}
                   1186: 			$loadavg =~ s/\s.*//g;
                   1187: 			my $loadpercent=100*$loadavg/$perlvar{'lonLoadLim'};
                   1188: 			print $client "$loadpercent\n";
                   1189: 		    } else {
                   1190: 			Reply($client, "refused\n", $userinput);
                   1191: 	       
                   1192: 		    }
1.127     albertel 1193: # -------------------------------------------------------------------- userload
1.161     foxr     1194: 		} elsif ($userinput =~ /^userload/) { # client only
                   1195: 		    if(isClient) {
                   1196: 			my $userloadpercent=&userload();
                   1197: 			print $client "$userloadpercent\n";
                   1198: 		    } else {
                   1199: 			Reply($client, "refused\n", $userinput);
                   1200: 		     
                   1201: 		    }
1.137     foxr     1202: #
                   1203: #        Transactions requiring encryption:
                   1204: #
1.54      harris41 1205: # ----------------------------------------------------------------- currentauth
1.161     foxr     1206: 		} elsif ($userinput =~ /^currentauth/) {
                   1207: 		    if (($wasenc==1)  && isClient) { # Encoded & client only.
                   1208: 			my ($cmd,$udom,$uname)=split(/:/,$userinput);
                   1209: 			my $result = GetAuthType($udom, $uname);
                   1210: 			if($result eq "nouser") {
                   1211: 			    print $client "unknown_user\n";
                   1212: 			}
                   1213: 			else {
                   1214: 			    print $client "$result\n"
                   1215: 			    }
                   1216: 		    } else {
                   1217: 			Reply($client, "refused\n", $userinput);
                   1218: 			
                   1219: 		    }
1.137     foxr     1220: #--------------------------------------------------------------------- pushfile
1.161     foxr     1221: 		} elsif($userinput =~ /^pushfile/) {	# encoded & manager.
                   1222: 		    if(($wasenc == 1) && isManager) {
                   1223: 			my $cert = GetCertificate($userinput);
                   1224: 			if(ValidManager($cert)) {
                   1225: 			    my $reply = PushFile($userinput);
                   1226: 			    print $client "$reply\n";
                   1227: 			} else {
                   1228: 			    print $client "refused\n";
                   1229: 			} 
                   1230: 		    } else {
                   1231: 			Reply($client, "refused\n", $userinput);
                   1232: 			
                   1233: 		    }
1.137     foxr     1234: #--------------------------------------------------------------------- reinit
1.161     foxr     1235: 		} elsif($userinput =~ /^reinit/) { # Encoded and manager
                   1236: 		    if (($wasenc == 1) && isManager) {
                   1237: 			my $cert = GetCertificate($userinput);
                   1238: 			if(ValidManager($cert)) {
                   1239: 			    chomp($userinput);
                   1240: 			    my $reply = ReinitProcess($userinput);
                   1241: 			    print $client  "$reply\n";
                   1242: 			} else {
                   1243: 			    print $client "refused\n";
                   1244: 			}
                   1245: 		    } else {
                   1246: 			Reply($client, "refused\n", $userinput);
                   1247: 
                   1248: 
                   1249: 		    }
1.1       albertel 1250: # ------------------------------------------------------------------------ auth
1.161     foxr     1251: 		} elsif ($userinput =~ /^auth/) { # Encoded and client only.
                   1252: 		    if (($wasenc==1) && isClient) {
                   1253: 			my ($cmd,$udom,$uname,$upass)=split(/:/,$userinput);
                   1254: 			chomp($upass);
                   1255: 			$upass=unescape($upass);
                   1256: 			my $proname=propath($udom,$uname);
                   1257: 			my $passfilename="$proname/passwd";
                   1258: 			if (-e $passfilename) {
                   1259: 			    my $pf = IO::File->new($passfilename);
                   1260: 			    my $realpasswd=<$pf>;
                   1261: 			    chomp($realpasswd);
                   1262: 			    my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
                   1263: 			    my $pwdcorrect=0;
                   1264: 			    if ($howpwd eq 'internal') {
                   1265: 				&Debug("Internal auth");
                   1266: 				$pwdcorrect=
                   1267: 				    (crypt($upass,$contentpwd) eq $contentpwd);
                   1268: 			    } elsif ($howpwd eq 'unix') {
                   1269: 				&Debug("Unix auth");
                   1270: 				if((getpwnam($uname))[1] eq "") { #no such user!
                   1271: 				    $pwdcorrect = 0;
                   1272: 				} else {
                   1273: 				    $contentpwd=(getpwnam($uname))[1];
                   1274: 				    my $pwauth_path="/usr/local/sbin/pwauth";
                   1275: 				    unless ($contentpwd eq 'x') {
                   1276: 					$pwdcorrect=
                   1277: 					    (crypt($upass,$contentpwd) eq 
                   1278: 					     $contentpwd);
                   1279: 				    }
                   1280: 				    
                   1281: 				    elsif (-e $pwauth_path) {
                   1282: 					open PWAUTH, "|$pwauth_path" or
                   1283: 					    die "Cannot invoke authentication";
                   1284: 					print PWAUTH "$uname\n$upass\n";
                   1285: 					close PWAUTH;
                   1286: 					$pwdcorrect=!$?;
                   1287: 				    }
                   1288: 				}
                   1289: 			    } elsif ($howpwd eq 'krb4') {
                   1290: 				my $null=pack("C",0);
                   1291: 				unless ($upass=~/$null/) {
                   1292: 				    my $krb4_error = &Authen::Krb4::get_pw_in_tkt
                   1293: 					($uname,"",$contentpwd,'krbtgt',
                   1294: 					 $contentpwd,1,$upass);
                   1295: 				    if (!$krb4_error) {
                   1296: 					$pwdcorrect = 1;
                   1297: 				    } else { 
                   1298: 					$pwdcorrect=0; 
                   1299: 					# log error if it is not a bad password
                   1300: 					if ($krb4_error != 62) {
                   1301: 					    &logthis('krb4:'.$uname.','.$contentpwd.','.
                   1302: 						     &Authen::Krb4::get_err_txt($Authen::Krb4::error));
                   1303: 					}
                   1304: 				    }
                   1305: 				}
                   1306: 			    } elsif ($howpwd eq 'krb5') {
                   1307: 				my $null=pack("C",0);
                   1308: 				unless ($upass=~/$null/) {
                   1309: 				    my $krbclient=&Authen::Krb5::parse_name($uname.'@'.$contentpwd);
                   1310: 				    my $krbservice="krbtgt/".$contentpwd."\@".$contentpwd;
                   1311: 				    my $krbserver=&Authen::Krb5::parse_name($krbservice);
                   1312: 				    my $credentials=&Authen::Krb5::cc_default();
                   1313: 				    $credentials->initialize($krbclient);
                   1314: 				    my $krbreturn = 
                   1315: 					&Authen::Krb5::get_in_tkt_with_password(
                   1316: 										$krbclient,$krbserver,$upass,$credentials);
1.92      albertel 1317: #				  unless ($krbreturn) {
                   1318: #				      &logthis("Krb5 Error: ".
                   1319: #					       &Authen::Krb5::error());
                   1320: #				  }
1.161     foxr     1321: 				    $pwdcorrect = ($krbreturn == 1);
                   1322: 				} else { $pwdcorrect=0; }
                   1323: 			    } elsif ($howpwd eq 'localauth') {
                   1324: 				$pwdcorrect=&localauth::localauth($uname,$upass,
                   1325: 								  $contentpwd);
                   1326: 			    }
                   1327: 			    if ($pwdcorrect) {
                   1328: 				print $client "authorized\n";
                   1329: 			    } else {
                   1330: 				print $client "non_authorized\n";
                   1331: 			    }  
                   1332: 			} else {
                   1333: 			    print $client "unknown_user\n";
                   1334: 			}
                   1335: 		    } else {
                   1336: 			Reply($client, "refused\n", $userinput);
                   1337: 		       
                   1338: 		    }
1.1       albertel 1339: # ---------------------------------------------------------------------- passwd
1.161     foxr     1340: 		} elsif ($userinput =~ /^passwd/) { # encoded and client
                   1341: 		    if (($wasenc==1) && isClient) {
                   1342: 			my 
                   1343: 			    ($cmd,$udom,$uname,$upass,$npass)=split(/:/,$userinput);
                   1344: 			chomp($npass);
                   1345: 			$upass=&unescape($upass);
                   1346: 			$npass=&unescape($npass);
                   1347: 			&Debug("Trying to change password for $uname");
                   1348: 			my $proname=propath($udom,$uname);
                   1349: 			my $passfilename="$proname/passwd";
                   1350: 			if (-e $passfilename) {
                   1351: 			    my $realpasswd;
                   1352: 			    { my $pf = IO::File->new($passfilename);
                   1353: 			      $realpasswd=<$pf>; }
                   1354: 			    chomp($realpasswd);
                   1355: 			    my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
                   1356: 			    if ($howpwd eq 'internal') {
                   1357: 				&Debug("internal auth");
                   1358: 				if (crypt($upass,$contentpwd) eq $contentpwd) {
                   1359: 				    my $salt=time;
                   1360: 				    $salt=substr($salt,6,2);
                   1361: 				    my $ncpass=crypt($npass,$salt);
                   1362: 				    {
                   1363: 					my $pf;
                   1364: 					if ($pf = IO::File->new(">$passfilename")) {
                   1365: 					    print $pf "internal:$ncpass\n";
                   1366: 					    &logthis("Result of password change for $uname: pwchange_success");
                   1367: 					    print $client "ok\n";
                   1368: 					} else {
                   1369: 					    &logthis("Unable to open $uname passwd to change password");
                   1370: 					    print $client "non_authorized\n";
                   1371: 					}
                   1372: 				    }             
                   1373: 				    
                   1374: 				} else {
                   1375: 				    print $client "non_authorized\n";
                   1376: 				}
                   1377: 			    } elsif ($howpwd eq 'unix') {
                   1378: 				# Unix means we have to access /etc/password
                   1379: 				# one way or another.
                   1380: 				# First: Make sure the current password is
                   1381: 				#        correct
                   1382: 				&Debug("auth is unix");
                   1383: 				$contentpwd=(getpwnam($uname))[1];
                   1384: 				my $pwdcorrect = "0";
                   1385: 				my $pwauth_path="/usr/local/sbin/pwauth";
                   1386: 				unless ($contentpwd eq 'x') {
                   1387: 				    $pwdcorrect=
                   1388: 					(crypt($upass,$contentpwd) eq $contentpwd);
                   1389: 				} elsif (-e $pwauth_path) {
                   1390: 				    open PWAUTH, "|$pwauth_path" or
                   1391: 					die "Cannot invoke authentication";
                   1392: 				    print PWAUTH "$uname\n$upass\n";
                   1393: 				    close PWAUTH;
                   1394: 				    &Debug("exited pwauth with $? ($uname,$upass) ");
                   1395: 				    $pwdcorrect=($? == 0);
                   1396: 				}
                   1397: 				if ($pwdcorrect) {
                   1398: 				    my $execdir=$perlvar{'lonDaemons'};
                   1399: 				    &Debug("Opening lcpasswd pipeline");
                   1400: 				    my $pf = IO::File->new("|$execdir/lcpasswd > $perlvar{'lonDaemons'}/logs/lcpasswd.log");
                   1401: 				    print $pf "$uname\n$npass\n$npass\n";
                   1402: 				    close $pf;
                   1403: 				    my $err = $?;
                   1404: 				    my $result = ($err>0 ? 'pwchange_failure' 
                   1405: 						  : 'ok');
                   1406: 				    &logthis("Result of password change for $uname: ".
                   1407: 					     &lcpasswdstrerror($?));
                   1408: 				    print $client "$result\n";
                   1409: 				} else {
                   1410: 				    print $client "non_authorized\n";
                   1411: 				}
                   1412: 			    } else {
                   1413: 				print $client "auth_mode_error\n";
                   1414: 			    }  
                   1415: 			} else {
                   1416: 			    print $client "unknown_user\n";
                   1417: 			}
                   1418: 		    } else {
                   1419: 			Reply($client, "refused\n", $userinput);
                   1420: 		       
                   1421: 		    }
1.31      www      1422: # -------------------------------------------------------------------- makeuser
1.161     foxr     1423: 		} elsif ($userinput =~ /^makeuser/) { # encoded and client.
                   1424: 		    &Debug("Make user received");
                   1425: 		    my $oldumask=umask(0077);
                   1426: 		    if (($wasenc==1) && isClient) {
                   1427: 			my 
                   1428: 			    ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);
                   1429: 			&Debug("cmd =".$cmd." $udom =".$udom.
                   1430: 			       " uname=".$uname);
                   1431: 			chomp($npass);
                   1432: 			$npass=&unescape($npass);
                   1433: 			my $proname=propath($udom,$uname);
                   1434: 			my $passfilename="$proname/passwd";
                   1435: 			&Debug("Password file created will be:".
                   1436: 			       $passfilename);
                   1437: 			if (-e $passfilename) {
                   1438: 			    print $client "already_exists\n";
                   1439: 			} elsif ($udom ne $currentdomainid) {
                   1440: 			    print $client "not_right_domain\n";
                   1441: 			} else {
                   1442: 			    my @fpparts=split(/\//,$proname);
                   1443: 			    my $fpnow=$fpparts[0].'/'.$fpparts[1].'/'.$fpparts[2];
                   1444: 			    my $fperror='';
                   1445: 			    for (my $i=3;$i<=$#fpparts;$i++) {
                   1446: 				$fpnow.='/'.$fpparts[$i]; 
                   1447: 				unless (-e $fpnow) {
                   1448: 				    unless (mkdir($fpnow,0777)) {
                   1449: 					$fperror="error: ".($!+0)
                   1450: 					    ." mkdir failed while attempting "
1.165.2.1  albertel 1451: 					    ."makeuser";
1.161     foxr     1452: 				    }
                   1453: 				}
                   1454: 			    }
                   1455: 			    unless ($fperror) {
                   1456: 				my $result=&make_passwd_file($uname, $umode,$npass,
                   1457: 							     $passfilename);
                   1458: 				print $client $result;
                   1459: 			    } else {
                   1460: 				print $client "$fperror\n";
                   1461: 			    }
                   1462: 			}
                   1463: 		    } else {
                   1464: 			Reply($client, "refused\n", $userinput);
                   1465: 	      
                   1466: 		    }
                   1467: 		    umask($oldumask);
1.55      harris41 1468: # -------------------------------------------------------------- changeuserauth
1.161     foxr     1469: 		} elsif ($userinput =~ /^changeuserauth/) { # encoded & client
                   1470: 		    &Debug("Changing authorization");
                   1471: 		    if (($wasenc==1) && isClient) {
                   1472: 			my 
                   1473: 			    ($cmd,$udom,$uname,$umode,$npass)=split(/:/,$userinput);
                   1474: 			chomp($npass);
                   1475: 			&Debug("cmd = ".$cmd." domain= ".$udom.
                   1476: 			       "uname =".$uname." umode= ".$umode);
                   1477: 			$npass=&unescape($npass);
                   1478: 			my $proname=&propath($udom,$uname);
                   1479: 			my $passfilename="$proname/passwd";
                   1480: 			if ($udom ne $currentdomainid) {
                   1481: 			    print $client "not_right_domain\n";
                   1482: 			} else {
                   1483: 			    my $result=&make_passwd_file($uname, $umode,$npass,
                   1484: 							 $passfilename);
                   1485: 			    print $client $result;
                   1486: 			}
                   1487: 		    } else {
                   1488: 			Reply($client, "refused\n", $userinput);
                   1489: 		   
                   1490: 		    }
1.1       albertel 1491: # ------------------------------------------------------------------------ home
1.161     foxr     1492: 		} elsif ($userinput =~ /^home/) { # client clear or encoded
                   1493: 		    if(isClient) {
                   1494: 			my ($cmd,$udom,$uname)=split(/:/,$userinput);
                   1495: 			chomp($uname);
                   1496: 			my $proname=propath($udom,$uname);
                   1497: 			if (-e $proname) {
                   1498: 			    print $client "found\n";
                   1499: 			} else {
                   1500: 			    print $client "not_found\n";
                   1501: 			}
                   1502: 		    } else {
                   1503: 			Reply($client, "refused\n", $userinput);
                   1504: 
                   1505: 		    }
1.1       albertel 1506: # ---------------------------------------------------------------------- update
1.161     foxr     1507: 		} elsif ($userinput =~ /^update/) { # client clear or encoded.
                   1508: 		    if(isClient) {
                   1509: 			my ($cmd,$fname)=split(/:/,$userinput);
                   1510: 			my $ownership=ishome($fname);
                   1511: 			if ($ownership eq 'not_owner') {
                   1512: 			    if (-e $fname) {
                   1513: 				my ($dev,$ino,$mode,$nlink,
                   1514: 				    $uid,$gid,$rdev,$size,
                   1515: 				    $atime,$mtime,$ctime,
                   1516: 				    $blksize,$blocks)=stat($fname);
                   1517: 				my $now=time;
                   1518: 				my $since=$now-$atime;
                   1519: 				if ($since>$perlvar{'lonExpire'}) {
                   1520: 				    my $reply=
                   1521: 					&reply("unsub:$fname","$clientname");
                   1522: 				    unlink("$fname");
                   1523: 				} else {
                   1524: 				    my $transname="$fname.in.transfer";
                   1525: 				    my $remoteurl=
                   1526: 					&reply("sub:$fname","$clientname");
                   1527: 				    my $response;
                   1528: 				    {
                   1529: 					my $ua=new LWP::UserAgent;
                   1530: 					my $request=new HTTP::Request('GET',"$remoteurl");
                   1531: 					$response=$ua->request($request,$transname);
                   1532: 				    }
                   1533: 				    if ($response->is_error()) {
                   1534: 					unlink($transname);
                   1535: 					my $message=$response->status_line;
                   1536: 					&logthis(
                   1537: 						 "LWP GET: $message for $fname ($remoteurl)");
                   1538: 				    } else {
                   1539: 					if ($remoteurl!~/\.meta$/) {
                   1540: 					    my $ua=new LWP::UserAgent;
                   1541: 					    my $mrequest=
                   1542: 						new HTTP::Request('GET',$remoteurl.'.meta');
                   1543: 					    my $mresponse=
                   1544: 						$ua->request($mrequest,$fname.'.meta');
                   1545: 					    if ($mresponse->is_error()) {
                   1546: 						unlink($fname.'.meta');
                   1547: 					    }
                   1548: 					}
                   1549: 					rename($transname,$fname);
                   1550: 				    }
                   1551: 				}
                   1552: 				print $client "ok\n";
                   1553: 			    } else {
                   1554: 				print $client "not_found\n";
                   1555: 			    }
                   1556: 			} else {
                   1557: 			    print $client "rejected\n";
                   1558: 			}
                   1559: 		    } else {
                   1560: 			Reply($client, "refused\n", $userinput);
                   1561: 
                   1562: 		    }
1.85      www      1563: # -------------------------------------- fetch a user file from a remote server
1.161     foxr     1564: 		} elsif ($userinput =~ /^fetchuserfile/) { # Client clear or enc.
                   1565: 		    if(isClient) {
                   1566: 			my ($cmd,$fname)=split(/:/,$userinput);
                   1567: 			my ($udom,$uname,$ufile)=split(/\//,$fname);
                   1568: 			my $udir=propath($udom,$uname).'/userfiles';
                   1569: 			unless (-e $udir) { mkdir($udir,0770); }
                   1570: 			if (-e $udir) {
                   1571: 			    $ufile=~s/^[\.\~]+//;
                   1572: 			    $ufile=~s/\///g;
                   1573: 			    my $destname=$udir.'/'.$ufile;
                   1574: 			    my $transname=$udir.'/'.$ufile.'.in.transit';
                   1575: 			    my $remoteurl='http://'.$clientip.'/userfiles/'.$fname;
                   1576: 			    my $response;
                   1577: 			    {
                   1578: 				my $ua=new LWP::UserAgent;
                   1579: 				my $request=new HTTP::Request('GET',"$remoteurl");
                   1580: 				$response=$ua->request($request,$transname);
                   1581: 			    }
                   1582: 			    if ($response->is_error()) {
                   1583: 				unlink($transname);
                   1584: 				my $message=$response->status_line;
                   1585: 				&logthis("LWP GET: $message for $fname ($remoteurl)");
                   1586: 				print $client "failed\n";
                   1587: 			    } else {
                   1588: 				if (!rename($transname,$destname)) {
                   1589: 				    &logthis("Unable to move $transname to $destname");
                   1590: 				    unlink($transname);
                   1591: 				    print $client "failed\n";
                   1592: 				} else {
                   1593: 				    print $client "ok\n";
                   1594: 				}
                   1595: 			    }
                   1596: 			} else {
                   1597: 			    print $client "not_home\n";
                   1598: 			}
                   1599: 		    } else {
                   1600: 			Reply($client, "refused\n", $userinput);
                   1601: 
                   1602: 		    }
1.85      www      1603: # ------------------------------------------ authenticate access to a user file
1.161     foxr     1604: 		} elsif ($userinput =~ /^tokenauthuserfile/) { # Client only
                   1605: 		    if(isClient) {
                   1606: 			my ($cmd,$fname,$session)=split(/:/,$userinput);
                   1607: 			chomp($session);
                   1608: 			my $reply='non_auth';
                   1609: 			if (open(ENVIN,$perlvar{'lonIDsDir'}.'/'.
                   1610: 				 $session.'.id')) {
                   1611: 			    while (my $line=<ENVIN>) {
                   1612: 				if ($line=~/userfile\.$fname\=/) { $reply='ok'; }
                   1613: 			    }
                   1614: 			    close(ENVIN);
                   1615: 			    print $client $reply."\n";
                   1616: 			} else {
                   1617: 			    print $client "invalid_token\n";
                   1618: 			}
                   1619: 		    } else {
                   1620: 			Reply($client, "refused\n", $userinput);
                   1621: 
                   1622: 		    }
1.1       albertel 1623: # ----------------------------------------------------------------- unsubscribe
1.161     foxr     1624: 		} elsif ($userinput =~ /^unsub/) {
                   1625: 		    if(isClient) {
                   1626: 			my ($cmd,$fname)=split(/:/,$userinput);
                   1627: 			if (-e $fname) {
                   1628: 			    print $client &unsub($client,$fname,$clientip);
                   1629: 			} else {
                   1630: 			    print $client "not_found\n";
                   1631: 			}
                   1632: 		    } else {
                   1633: 			Reply($client, "refused\n", $userinput);
                   1634: 
                   1635: 		    }
1.1       albertel 1636: # ------------------------------------------------------------------- subscribe
1.161     foxr     1637: 		} elsif ($userinput =~ /^sub/) {
                   1638: 		    if(isClient) {
                   1639: 			print $client &subscribe($userinput,$clientip);
                   1640: 		    } else {
                   1641: 			Reply($client, "refused\n", $userinput);
                   1642: 
                   1643: 		    }
1.102     www      1644: # ------------------------------------------------------------- current version
1.161     foxr     1645: 		} elsif ($userinput =~ /^currentversion/) {
                   1646: 		    if(isClient) {
                   1647: 			my ($cmd,$fname)=split(/:/,$userinput);
                   1648: 			print $client &currentversion($fname)."\n";
                   1649: 		    } else {
                   1650: 			Reply($client, "refused\n", $userinput);
                   1651: 
                   1652: 		    }
1.12      harris41 1653: # ------------------------------------------------------------------------- log
1.161     foxr     1654: 		} elsif ($userinput =~ /^log/) {
                   1655: 		    if(isClient) {
                   1656: 			my ($cmd,$udom,$uname,$what)=split(/:/,$userinput);
                   1657: 			chomp($what);
                   1658: 			my $proname=propath($udom,$uname);
                   1659: 			my $now=time;
                   1660: 			{
                   1661: 			    my $hfh;
                   1662: 			    if ($hfh=IO::File->new(">>$proname/activity.log")) { 
                   1663: 				print $hfh "$now:$clientname:$what\n";
                   1664: 				print $client "ok\n"; 
                   1665: 			    } else {
                   1666: 				print $client "error: ".($!+0)
                   1667: 				    ." IO::File->new Failed "
                   1668: 				    ."while attempting log\n";
                   1669: 			    }
                   1670: 			}
                   1671: 		    } else {
                   1672: 			Reply($client, "refused\n", $userinput);
                   1673: 
                   1674: 		    }
1.1       albertel 1675: # ------------------------------------------------------------------------- put
1.161     foxr     1676: 		} elsif ($userinput =~ /^put/) {
                   1677: 		    if(isClient) {
                   1678: 			my ($cmd,$udom,$uname,$namespace,$what)
                   1679: 			    =split(/:/,$userinput);
                   1680: 			$namespace=~s/\//\_/g;
                   1681: 			$namespace=~s/\W//g;
                   1682: 			if ($namespace ne 'roles') {
                   1683: 			    chomp($what);
                   1684: 			    my $proname=propath($udom,$uname);
                   1685: 			    my $now=time;
                   1686: 			    unless ($namespace=~/^nohist\_/) {
                   1687: 				my $hfh;
                   1688: 				if (
                   1689: 				    $hfh=IO::File->new(">>$proname/$namespace.hist")
                   1690: 				    ) { print $hfh "P:$now:$what\n"; }
                   1691: 			    }
                   1692: 			    my @pairs=split(/\&/,$what);
                   1693: 			    my %hash;
                   1694: 			    if (tie(%hash,'GDBM_File',
                   1695: 				    "$proname/$namespace.db",
                   1696: 				    &GDBM_WRCREAT(),0640)) {
                   1697: 				foreach my $pair (@pairs) {
                   1698: 				    my ($key,$value)=split(/=/,$pair);
                   1699: 				    $hash{$key}=$value;
1.162     matthew  1700: 				}
                   1701: 				if (untie(%hash)) {
                   1702: 				    print $client "ok\n";
                   1703: 				} else {
                   1704: 				    print $client "error: ".($!+0)
                   1705: 					." untie(GDBM) failed ".
                   1706: 					"while attempting put\n";
                   1707: 				}
                   1708: 			    } else {
                   1709: 				print $client "error: ".($!)
                   1710: 				    ." tie(GDBM) Failed ".
                   1711: 				    "while attempting put\n";
                   1712: 			    }
                   1713: 			} else {
                   1714: 			    print $client "refused\n";
                   1715: 			}
                   1716: 		    } else {
                   1717: 			Reply($client, "refused\n", $userinput);
                   1718: 
                   1719: 		    }
                   1720: # ------------------------------------------------------------------- inc
                   1721: 		} elsif ($userinput =~ /^inc:/) {
                   1722: 		    if(isClient) {
                   1723: 			my ($cmd,$udom,$uname,$namespace,$what)
                   1724: 			    =split(/:/,$userinput);
                   1725: 			$namespace=~s/\//\_/g;
                   1726: 			$namespace=~s/\W//g;
                   1727: 			if ($namespace ne 'roles') {
                   1728: 			    chomp($what);
                   1729: 			    my $proname=propath($udom,$uname);
                   1730: 			    my $now=time;
                   1731: 			    unless ($namespace=~/^nohist\_/) {
                   1732: 				my $hfh;
                   1733: 				if (
                   1734: 				    $hfh=IO::File->new(">>$proname/$namespace.hist")
                   1735: 				    ) { print $hfh "P:$now:$what\n"; }
                   1736: 			    }
                   1737: 			    my @pairs=split(/\&/,$what);
                   1738: 			    my %hash;
                   1739: 			    if (tie(%hash,'GDBM_File',
                   1740: 				    "$proname/$namespace.db",
                   1741: 				    &GDBM_WRCREAT(),0640)) {
                   1742: 				foreach my $pair (@pairs) {
                   1743: 				    my ($key,$value)=split(/=/,$pair);
                   1744:                                     # We could check that we have a number...
                   1745:                                     if (! defined($value) || $value eq '') {
                   1746:                                         $value = 1;
                   1747:                                     }
                   1748: 				    $hash{$key}+=$value;
1.161     foxr     1749: 				}
                   1750: 				if (untie(%hash)) {
                   1751: 				    print $client "ok\n";
                   1752: 				} else {
                   1753: 				    print $client "error: ".($!+0)
                   1754: 					." untie(GDBM) failed ".
                   1755: 					"while attempting put\n";
                   1756: 				}
                   1757: 			    } else {
                   1758: 				print $client "error: ".($!)
                   1759: 				    ." tie(GDBM) Failed ".
                   1760: 				    "while attempting put\n";
                   1761: 			    }
                   1762: 			} else {
                   1763: 			    print $client "refused\n";
                   1764: 			}
                   1765: 		    } else {
                   1766: 			Reply($client, "refused\n", $userinput);
                   1767: 
                   1768: 		    }
1.6       www      1769: # -------------------------------------------------------------------- rolesput
1.161     foxr     1770: 		} elsif ($userinput =~ /^rolesput/) {
                   1771: 		    if(isClient) {
                   1772: 			&Debug("rolesput");
                   1773: 			if ($wasenc==1) {
                   1774: 			    my ($cmd,$exedom,$exeuser,$udom,$uname,$what)
                   1775: 				=split(/:/,$userinput);
                   1776: 			    &Debug("cmd = ".$cmd." exedom= ".$exedom.
                   1777: 				   "user = ".$exeuser." udom=".$udom.
                   1778: 				   "what = ".$what);
                   1779: 			    my $namespace='roles';
                   1780: 			    chomp($what);
                   1781: 			    my $proname=propath($udom,$uname);
                   1782: 			    my $now=time;
                   1783: 			    {
                   1784: 				my $hfh;
                   1785: 				if (
                   1786: 				    $hfh=IO::File->new(">>$proname/$namespace.hist")
                   1787: 				    ) { 
                   1788: 				    print $hfh "P:$now:$exedom:$exeuser:$what\n";
                   1789: 				}
                   1790: 			    }
                   1791: 			    my @pairs=split(/\&/,$what);
                   1792: 			    my %hash;
                   1793: 			    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
                   1794: 				foreach my $pair (@pairs) {
                   1795: 				    my ($key,$value)=split(/=/,$pair);
                   1796: 				    &ManagePermissions($key, $udom, $uname,
                   1797: 						       &GetAuthType( $udom, 
                   1798: 								     $uname));
                   1799: 				    $hash{$key}=$value;
                   1800: 				}
                   1801: 				if (untie(%hash)) {
                   1802: 				    print $client "ok\n";
                   1803: 				} else {
                   1804: 				    print $client "error: ".($!+0)
                   1805: 					." untie(GDBM) Failed ".
                   1806: 					"while attempting rolesput\n";
                   1807: 				}
                   1808: 			    } else {
                   1809: 				print $client "error: ".($!+0)
                   1810: 				    ." tie(GDBM) Failed ".
                   1811: 				    "while attempting rolesput\n";
                   1812: 			    }
                   1813: 			} else {
                   1814: 			    print $client "refused\n";
                   1815: 			}
                   1816: 		    } else {
                   1817: 			Reply($client, "refused\n", $userinput);
                   1818: 		  
                   1819: 		    }
1.117     www      1820: # -------------------------------------------------------------------- rolesdel
1.161     foxr     1821: 		} elsif ($userinput =~ /^rolesdel/) {
                   1822: 		    if(isClient) {
                   1823: 			&Debug("rolesdel");
                   1824: 			if ($wasenc==1) {
                   1825: 			    my ($cmd,$exedom,$exeuser,$udom,$uname,$what)
                   1826: 				=split(/:/,$userinput);
                   1827: 			    &Debug("cmd = ".$cmd." exedom= ".$exedom.
                   1828: 				   "user = ".$exeuser." udom=".$udom.
                   1829: 				   "what = ".$what);
                   1830: 			    my $namespace='roles';
                   1831: 			    chomp($what);
                   1832: 			    my $proname=propath($udom,$uname);
                   1833: 			    my $now=time;
                   1834: 			    {
                   1835: 				my $hfh;
                   1836: 				if (
                   1837: 				    $hfh=IO::File->new(">>$proname/$namespace.hist")
                   1838: 				    ) { 
                   1839: 				    print $hfh "D:$now:$exedom:$exeuser:$what\n";
                   1840: 				}
                   1841: 			    }
                   1842: 			    my @rolekeys=split(/\&/,$what);
                   1843: 			    my %hash;
                   1844: 			    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
                   1845: 				foreach my $key (@rolekeys) {
                   1846: 				    delete $hash{$key};
                   1847: 				}
                   1848: 				if (untie(%hash)) {
                   1849: 				    print $client "ok\n";
                   1850: 				} else {
                   1851: 				    print $client "error: ".($!+0)
                   1852: 					." untie(GDBM) Failed ".
                   1853: 					"while attempting rolesdel\n";
                   1854: 				}
                   1855: 			    } else {
                   1856: 				print $client "error: ".($!+0)
                   1857: 				    ." tie(GDBM) Failed ".
                   1858: 				    "while attempting rolesdel\n";
                   1859: 			    }
                   1860: 			} else {
                   1861: 			    print $client "refused\n";
                   1862: 			}
                   1863: 		    } else {
                   1864: 			Reply($client, "refused\n", $userinput);
                   1865: 		      
                   1866: 		    }
1.1       albertel 1867: # ------------------------------------------------------------------------- get
1.161     foxr     1868: 		} elsif ($userinput =~ /^get/) {
                   1869: 		    if(isClient) {
                   1870: 			my ($cmd,$udom,$uname,$namespace,$what)
                   1871: 			    =split(/:/,$userinput);
                   1872: 			$namespace=~s/\//\_/g;
                   1873: 			$namespace=~s/\W//g;
                   1874: 			chomp($what);
                   1875: 			my @queries=split(/\&/,$what);
                   1876: 			my $proname=propath($udom,$uname);
                   1877: 			my $qresult='';
                   1878: 			my %hash;
                   1879: 			if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                   1880: 			    for (my $i=0;$i<=$#queries;$i++) {
                   1881: 				$qresult.="$hash{$queries[$i]}&";
                   1882: 			    }
                   1883: 			    if (untie(%hash)) {
                   1884: 				$qresult=~s/\&$//;
                   1885: 				print $client "$qresult\n";
                   1886: 			    } else {
                   1887: 				print $client "error: ".($!+0)
                   1888: 				    ." untie(GDBM) Failed ".
                   1889: 				    "while attempting get\n";
                   1890: 			    }
                   1891: 			} else {
                   1892: 			    if ($!+0 == 2) {
                   1893: 				print $client "error:No such file or ".
                   1894: 				    "GDBM reported bad block error\n";
                   1895: 			    } else {
                   1896: 				print $client "error: ".($!+0)
                   1897: 				    ." tie(GDBM) Failed ".
                   1898: 				    "while attempting get\n";
                   1899: 			    }
                   1900: 			}
                   1901: 		    } else {
                   1902: 			Reply($client, "refused\n", $userinput);
                   1903: 		       
                   1904: 		    }
1.1       albertel 1905: # ------------------------------------------------------------------------ eget
1.161     foxr     1906: 		} elsif ($userinput =~ /^eget/) {
                   1907: 		    if (isClient) {
                   1908: 			my ($cmd,$udom,$uname,$namespace,$what)
                   1909: 			    =split(/:/,$userinput);
                   1910: 			$namespace=~s/\//\_/g;
                   1911: 			$namespace=~s/\W//g;
                   1912: 			chomp($what);
                   1913: 			my @queries=split(/\&/,$what);
                   1914: 			my $proname=propath($udom,$uname);
                   1915: 			my $qresult='';
                   1916: 			my %hash;
                   1917: 			if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                   1918: 			    for (my $i=0;$i<=$#queries;$i++) {
                   1919: 				$qresult.="$hash{$queries[$i]}&";
                   1920: 			    }
                   1921: 			    if (untie(%hash)) {
                   1922: 				$qresult=~s/\&$//;
                   1923: 				if ($cipher) {
                   1924: 				    my $cmdlength=length($qresult);
                   1925: 				    $qresult.="         ";
                   1926: 				    my $encqresult='';
                   1927: 				    for 
                   1928: 					(my $encidx=0;$encidx<=$cmdlength;$encidx+=8) {
                   1929: 					    $encqresult.=
                   1930: 						unpack("H16",
                   1931: 						       $cipher->encrypt(substr($qresult,$encidx,8)));
                   1932: 					}
                   1933: 				    print $client "enc:$cmdlength:$encqresult\n";
                   1934: 				} else {
                   1935: 				    print $client "error:no_key\n";
                   1936: 				}
                   1937: 			    } else {
                   1938: 				print $client "error: ".($!+0)
                   1939: 				    ." untie(GDBM) Failed ".
                   1940: 				    "while attempting eget\n";
                   1941: 			    }
                   1942: 			} else {
                   1943: 			    print $client "error: ".($!+0)
                   1944: 				." tie(GDBM) Failed ".
                   1945: 				"while attempting eget\n";
                   1946: 			}
                   1947: 		    } else {
                   1948: 			Reply($client, "refused\n", $userinput);
                   1949: 		    
                   1950: 		    }
1.1       albertel 1951: # ------------------------------------------------------------------------- del
1.161     foxr     1952: 		} elsif ($userinput =~ /^del/) {
                   1953: 		    if(isClient) {
                   1954: 			my ($cmd,$udom,$uname,$namespace,$what)
                   1955: 			    =split(/:/,$userinput);
                   1956: 			$namespace=~s/\//\_/g;
                   1957: 			$namespace=~s/\W//g;
                   1958: 			chomp($what);
                   1959: 			my $proname=propath($udom,$uname);
                   1960: 			my $now=time;
                   1961: 			unless ($namespace=~/^nohist\_/) {
                   1962: 			    my $hfh;
                   1963: 			    if (
                   1964: 				$hfh=IO::File->new(">>$proname/$namespace.hist")
                   1965: 				) { print $hfh "D:$now:$what\n"; }
                   1966: 			}
                   1967: 			my @keys=split(/\&/,$what);
                   1968: 			my %hash;
                   1969: 			if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
                   1970: 			    foreach my $key (@keys) {
1.165.2.2  albertel 1971: 				delete($hash{$key});
1.161     foxr     1972: 			    }
                   1973: 			    if (untie(%hash)) {
                   1974: 				print $client "ok\n";
                   1975: 			    } else {
                   1976: 				print $client "error: ".($!+0)
                   1977: 				    ." untie(GDBM) Failed ".
                   1978: 				    "while attempting del\n";
                   1979: 			    }
                   1980: 			} else {
                   1981: 			    print $client "error: ".($!+0)
                   1982: 				." tie(GDBM) Failed ".
                   1983: 				"while attempting del\n";
                   1984: 			}
                   1985: 		    } else {
                   1986: 			Reply($client, "refused\n", $userinput);
                   1987: 			
                   1988: 		    }
1.1       albertel 1989: # ------------------------------------------------------------------------ keys
1.161     foxr     1990: 		} elsif ($userinput =~ /^keys/) {
                   1991: 		    if(isClient) {
                   1992: 			my ($cmd,$udom,$uname,$namespace)
                   1993: 			    =split(/:/,$userinput);
                   1994: 			$namespace=~s/\//\_/g;
                   1995: 			$namespace=~s/\W//g;
                   1996: 			my $proname=propath($udom,$uname);
                   1997: 			my $qresult='';
                   1998: 			my %hash;
                   1999: 			if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                   2000: 			    foreach my $key (keys %hash) {
                   2001: 				$qresult.="$key&";
                   2002: 			    }
                   2003: 			    if (untie(%hash)) {
                   2004: 				$qresult=~s/\&$//;
                   2005: 				print $client "$qresult\n";
                   2006: 			    } else {
                   2007: 				print $client "error: ".($!+0)
                   2008: 				    ." untie(GDBM) Failed ".
                   2009: 				    "while attempting keys\n";
                   2010: 			    }
                   2011: 			} else {
                   2012: 			    print $client "error: ".($!+0)
                   2013: 				." tie(GDBM) Failed ".
                   2014: 				"while attempting keys\n";
                   2015: 			}
                   2016: 		    } else {
                   2017: 			Reply($client, "refused\n", $userinput);
                   2018: 		   
                   2019: 		    }
1.105     matthew  2020: # ----------------------------------------------------------------- dumpcurrent
1.161     foxr     2021: 		} elsif ($userinput =~ /^currentdump/) {
                   2022: 		    if (isClient) {
                   2023: 			my ($cmd,$udom,$uname,$namespace)
                   2024: 			    =split(/:/,$userinput);
                   2025: 			$namespace=~s/\//\_/g;
                   2026: 			$namespace=~s/\W//g;
                   2027: 			my $qresult='';
                   2028: 			my $proname=propath($udom,$uname);
                   2029: 			my %hash;
                   2030: 			if (tie(%hash,'GDBM_File',
                   2031: 				"$proname/$namespace.db",
                   2032: 				&GDBM_READER(),0640)) {
                   2033: 			    # Structure of %data:
                   2034: 			    # $data{$symb}->{$parameter}=$value;
                   2035: 			    # $data{$symb}->{'v.'.$parameter}=$version;
                   2036: 			    # since $parameter will be unescaped, we do not
                   2037: 			    # have to worry about silly parameter names...
                   2038: 			    my %data = ();
                   2039: 			    while (my ($key,$value) = each(%hash)) {
                   2040: 				my ($v,$symb,$param) = split(/:/,$key);
                   2041: 				next if ($v eq 'version' || $symb eq 'keys');
                   2042: 				next if (exists($data{$symb}) && 
                   2043: 					 exists($data{$symb}->{$param}) &&
                   2044: 					 $data{$symb}->{'v.'.$param} > $v);
                   2045: 				$data{$symb}->{$param}=$value;
                   2046: 				$data{$symb}->{'v.'.$param}=$v;
                   2047: 			    }
                   2048: 			    if (untie(%hash)) {
                   2049: 				while (my ($symb,$param_hash) = each(%data)) {
                   2050: 				    while(my ($param,$value) = each (%$param_hash)){
                   2051: 					next if ($param =~ /^v\./);
                   2052: 					$qresult.=$symb.':'.$param.'='.$value.'&';
                   2053: 				    }
                   2054: 				}
                   2055: 				chop($qresult);
                   2056: 				print $client "$qresult\n";
                   2057: 			    } else {
                   2058: 				print $client "error: ".($!+0)
                   2059: 				    ." untie(GDBM) Failed ".
                   2060: 				    "while attempting currentdump\n";
                   2061: 			    }
                   2062: 			} else {
                   2063: 			    print $client "error: ".($!+0)
                   2064: 				." tie(GDBM) Failed ".
                   2065: 				"while attempting currentdump\n";
                   2066: 			}
                   2067: 		    } else {
                   2068: 			Reply($client, "refused\n", $userinput);
                   2069: 		    }
1.1       albertel 2070: # ------------------------------------------------------------------------ dump
1.161     foxr     2071: 		} elsif ($userinput =~ /^dump/) {
                   2072: 		    if(isClient) {
                   2073: 			my ($cmd,$udom,$uname,$namespace,$regexp)
                   2074: 			    =split(/:/,$userinput);
                   2075: 			$namespace=~s/\//\_/g;
                   2076: 			$namespace=~s/\W//g;
                   2077: 			if (defined($regexp)) {
                   2078: 			    $regexp=&unescape($regexp);
                   2079: 			} else {
                   2080: 			    $regexp='.';
                   2081: 			}
                   2082: 			my $qresult='';
                   2083: 			my $proname=propath($udom,$uname);
                   2084: 			my %hash;
                   2085: 			if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                   2086: 			       study($regexp);
                   2087: 			       while (my ($key,$value) = each(%hash)) {
                   2088: 				   if ($regexp eq '.') {
                   2089: 				       $qresult.=$key.'='.$value.'&';
                   2090: 				   } else {
                   2091: 				       my $unescapeKey = &unescape($key);
                   2092: 				       if (eval('$unescapeKey=~/$regexp/')) {
                   2093: 					   $qresult.="$key=$value&";
                   2094: 				       }
                   2095: 				   }
                   2096: 			       }
                   2097: 			       if (untie(%hash)) {
                   2098: 				   chop($qresult);
                   2099: 				   print $client "$qresult\n";
                   2100: 			       } else {
                   2101: 				   print $client "error: ".($!+0)
                   2102: 				       ." untie(GDBM) Failed ".
1.111     matthew  2103:                                        "while attempting dump\n";
1.161     foxr     2104: 			       }
                   2105: 			   } else {
                   2106: 			       print $client "error: ".($!+0)
                   2107: 				   ." tie(GDBM) Failed ".
                   2108: 				   "while attempting dump\n";
                   2109: 			   }
                   2110: 		    } else {
                   2111: 			Reply($client, "refused\n", $userinput);
                   2112: 		 
                   2113: 		    }
1.7       www      2114: # ----------------------------------------------------------------------- store
1.161     foxr     2115: 		} elsif ($userinput =~ /^store/) {
                   2116: 		    if(isClient) {
                   2117: 			my ($cmd,$udom,$uname,$namespace,$rid,$what)
                   2118: 			    =split(/:/,$userinput);
                   2119: 			$namespace=~s/\//\_/g;
                   2120: 			$namespace=~s/\W//g;
                   2121: 			if ($namespace ne 'roles') {
                   2122: 			    chomp($what);
                   2123: 			    my $proname=propath($udom,$uname);
                   2124: 			    my $now=time;
                   2125: 			    unless ($namespace=~/^nohist\_/) {
                   2126: 				my $hfh;
                   2127: 				if (
                   2128: 				    $hfh=IO::File->new(">>$proname/$namespace.hist")
                   2129: 				    ) { print $hfh "P:$now:$rid:$what\n"; }
                   2130: 			    }
                   2131: 			    my @pairs=split(/\&/,$what);
                   2132: 			    my %hash;
                   2133: 			    if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_WRCREAT(),0640)) {
                   2134: 				my @previouskeys=split(/&/,$hash{"keys:$rid"});
                   2135: 				my $key;
                   2136: 				$hash{"version:$rid"}++;
                   2137: 				my $version=$hash{"version:$rid"};
                   2138: 				my $allkeys=''; 
                   2139: 				foreach my $pair (@pairs) {
                   2140: 				    my ($key,$value)=split(/=/,$pair);
                   2141: 				    $allkeys.=$key.':';
                   2142: 				    $hash{"$version:$rid:$key"}=$value;
                   2143: 				}
                   2144: 				$hash{"$version:$rid:timestamp"}=$now;
                   2145: 				$allkeys.='timestamp';
                   2146: 				$hash{"$version:keys:$rid"}=$allkeys;
                   2147: 				if (untie(%hash)) {
                   2148: 				    print $client "ok\n";
                   2149: 				} else {
                   2150: 				    print $client "error: ".($!+0)
                   2151: 					." untie(GDBM) Failed ".
                   2152: 					"while attempting store\n";
                   2153: 				}
                   2154: 			    } else {
                   2155: 				print $client "error: ".($!+0)
                   2156: 				    ." tie(GDBM) Failed ".
                   2157: 				    "while attempting store\n";
                   2158: 			    }
                   2159: 			} else {
                   2160: 			    print $client "refused\n";
                   2161: 			}
                   2162: 		    } else {
                   2163: 			Reply($client, "refused\n", $userinput);
                   2164: 		     
                   2165: 		    }
1.7       www      2166: # --------------------------------------------------------------------- restore
1.161     foxr     2167: 		} elsif ($userinput =~ /^restore/) {
                   2168: 		    if(isClient) {
                   2169: 			my ($cmd,$udom,$uname,$namespace,$rid)
                   2170: 			    =split(/:/,$userinput);
                   2171: 			$namespace=~s/\//\_/g;
                   2172: 			$namespace=~s/\W//g;
                   2173: 			chomp($rid);
                   2174: 			my $proname=propath($udom,$uname);
                   2175: 			my $qresult='';
                   2176: 			my %hash;
                   2177: 			if (tie(%hash,'GDBM_File',"$proname/$namespace.db",&GDBM_READER(),0640)) {
                   2178: 			    my $version=$hash{"version:$rid"};
                   2179: 			    $qresult.="version=$version&";
                   2180: 			    my $scope;
                   2181: 			    for ($scope=1;$scope<=$version;$scope++) {
                   2182: 				my $vkeys=$hash{"$scope:keys:$rid"};
                   2183: 				my @keys=split(/:/,$vkeys);
                   2184: 				my $key;
                   2185: 				$qresult.="$scope:keys=$vkeys&";
                   2186: 				foreach $key (@keys) {
                   2187: 				    $qresult.="$scope:$key=".$hash{"$scope:$rid:$key"}."&";
                   2188: 				}                                  
                   2189: 			    }
                   2190: 			    if (untie(%hash)) {
                   2191: 				$qresult=~s/\&$//;
                   2192: 				print $client "$qresult\n";
                   2193: 			    } else {
                   2194: 				print $client "error: ".($!+0)
                   2195: 				    ." untie(GDBM) Failed ".
                   2196: 				    "while attempting restore\n";
                   2197: 			    }
                   2198: 			} else {
                   2199: 			    print $client "error: ".($!+0)
                   2200: 				." tie(GDBM) Failed ".
                   2201: 				"while attempting restore\n";
                   2202: 			}
                   2203: 		    } else  {
                   2204: 			Reply($client, "refused\n", $userinput);
                   2205: 		       
                   2206: 		    }
1.86      www      2207: # -------------------------------------------------------------------- chatsend
1.161     foxr     2208: 		} elsif ($userinput =~ /^chatsend/) {
                   2209: 		    if(isClient) {
                   2210: 			my ($cmd,$cdom,$cnum,$newpost)=split(/\:/,$userinput);
                   2211: 			&chatadd($cdom,$cnum,$newpost);
                   2212: 			print $client "ok\n";
                   2213: 		    } else {
                   2214: 			Reply($client, "refused\n", $userinput);
                   2215: 		      
                   2216: 		    }
1.86      www      2217: # -------------------------------------------------------------------- chatretr
1.161     foxr     2218: 		} elsif ($userinput =~ /^chatretr/) {
                   2219: 		    if(isClient) {
                   2220: 			my 
                   2221: 			    ($cmd,$cdom,$cnum,$udom,$uname)=split(/\:/,$userinput);
                   2222: 			my $reply='';
                   2223: 			foreach (&getchat($cdom,$cnum,$udom,$uname)) {
                   2224: 			    $reply.=&escape($_).':';
                   2225: 			}
                   2226: 			$reply=~s/\:$//;
                   2227: 			print $client $reply."\n";
                   2228: 		    } else {
                   2229: 			Reply($client, "refused\n", $userinput);
                   2230: 		       
                   2231: 		    }
1.12      harris41 2232: # ------------------------------------------------------------------- querysend
1.161     foxr     2233: 		} elsif ($userinput =~ /^querysend/) {
                   2234: 		    if(isClient) {
                   2235: 			my ($cmd,$query,
                   2236: 			    $arg1,$arg2,$arg3)=split(/\:/,$userinput);
                   2237: 			$query=~s/\n*$//g;
                   2238: 			print $client "".
                   2239: 			    sqlreply("$clientname\&$query".
                   2240: 				     "\&$arg1"."\&$arg2"."\&$arg3")."\n";
                   2241: 		    } else {
                   2242: 			Reply($client, "refused\n", $userinput);
                   2243: 		      
                   2244: 		    }
1.12      harris41 2245: # ------------------------------------------------------------------ queryreply
1.161     foxr     2246: 		} elsif ($userinput =~ /^queryreply/) {
                   2247: 		    if(isClient) {
                   2248: 			my ($cmd,$id,$reply)=split(/:/,$userinput); 
                   2249: 			my $store;
                   2250: 			my $execdir=$perlvar{'lonDaemons'};
                   2251: 			if ($store=IO::File->new(">$execdir/tmp/$id")) {
                   2252: 			    $reply=~s/\&/\n/g;
                   2253: 			    print $store $reply;
                   2254: 			    close $store;
                   2255: 			    my $store2=IO::File->new(">$execdir/tmp/$id.end");
                   2256: 			    print $store2 "done\n";
                   2257: 			    close $store2;
                   2258: 			    print $client "ok\n";
                   2259: 			}
                   2260: 			else {
                   2261: 			    print $client "error: ".($!+0)
                   2262: 				." IO::File->new Failed ".
                   2263: 				"while attempting queryreply\n";
                   2264: 			}
                   2265: 		    } else {
                   2266: 			Reply($client, "refused\n", $userinput);
                   2267: 		     
                   2268: 		    }
1.118     www      2269: # ----------------------------------------------------------------- courseidput
1.161     foxr     2270: 		} elsif ($userinput =~ /^courseidput/) {
                   2271: 		    if(isClient) {
                   2272: 			my ($cmd,$udom,$what)=split(/:/,$userinput);
                   2273: 			chomp($what);
                   2274: 			$udom=~s/\W//g;
                   2275: 			my $proname=
                   2276: 			    "$perlvar{'lonUsersDir'}/$udom/nohist_courseids";
                   2277: 			my $now=time;
                   2278: 			my @pairs=split(/\&/,$what);
                   2279: 			my %hash;
                   2280: 			if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_WRCREAT(),0640)) {
                   2281: 			    foreach my $pair (@pairs) {
                   2282: 				my ($key,$value)=split(/=/,$pair);
                   2283: 				$hash{$key}=$value.':'.$now;
                   2284: 			    }
                   2285: 			    if (untie(%hash)) {
                   2286: 				print $client "ok\n";
                   2287: 			    } else {
                   2288: 				print $client "error: ".($!+0)
                   2289: 				    ." untie(GDBM) Failed ".
                   2290: 				    "while attempting courseidput\n";
                   2291: 			    }
                   2292: 			} else {
                   2293: 			    print $client "error: ".($!+0)
                   2294: 				." tie(GDBM) Failed ".
                   2295: 				"while attempting courseidput\n";
                   2296: 			}
                   2297: 		    } else {
                   2298: 			Reply($client, "refused\n", $userinput);
                   2299: 		       
                   2300: 		    }
1.118     www      2301: # ---------------------------------------------------------------- courseiddump
1.161     foxr     2302: 		} elsif ($userinput =~ /^courseiddump/) {
                   2303: 		    if(isClient) {
                   2304: 			my ($cmd,$udom,$since,$description)
                   2305: 			    =split(/:/,$userinput);
                   2306: 			if (defined($description)) {
                   2307: 			    $description=&unescape($description);
                   2308: 			} else {
                   2309: 			    $description='.';
                   2310: 			}
                   2311: 			unless (defined($since)) { $since=0; }
                   2312: 			my $qresult='';
                   2313: 			my $proname=
                   2314: 			    "$perlvar{'lonUsersDir'}/$udom/nohist_courseids";
                   2315: 			my %hash;
                   2316: 			if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_READER(),0640)) {
                   2317: 			    while (my ($key,$value) = each(%hash)) {
                   2318: 				my ($descr,$lasttime)=split(/\:/,$value);
                   2319: 				if ($lasttime<$since) { next; }
                   2320: 				if ($description eq '.') {
                   2321: 				    $qresult.=$key.'='.$descr.'&';
                   2322: 				} else {
                   2323: 				    my $unescapeVal = &unescape($descr);
                   2324: 				    if (eval('$unescapeVal=~/$description/i')) {
                   2325: 					$qresult.="$key=$descr&";
                   2326: 				    }
                   2327: 				}
                   2328: 			    }
                   2329: 			    if (untie(%hash)) {
                   2330: 				chop($qresult);
                   2331: 				print $client "$qresult\n";
                   2332: 			    } else {
                   2333: 				print $client "error: ".($!+0)
                   2334: 				    ." untie(GDBM) Failed ".
                   2335: 				    "while attempting courseiddump\n";
                   2336: 			    }
                   2337: 			} else {
                   2338: 			    print $client "error: ".($!+0)
                   2339: 				." tie(GDBM) Failed ".
                   2340: 				"while attempting courseiddump\n";
                   2341: 			}
                   2342: 		    } else {
                   2343: 			Reply($client, "refused\n", $userinput);
                   2344: 		       
                   2345: 		    }
1.1       albertel 2346: # ----------------------------------------------------------------------- idput
1.161     foxr     2347: 		} elsif ($userinput =~ /^idput/) {
                   2348: 		    if(isClient) {
                   2349: 			my ($cmd,$udom,$what)=split(/:/,$userinput);
                   2350: 			chomp($what);
                   2351: 			$udom=~s/\W//g;
                   2352: 			my $proname="$perlvar{'lonUsersDir'}/$udom/ids";
                   2353: 			my $now=time;
                   2354: 			{
                   2355: 			    my $hfh;
                   2356: 			    if (
                   2357: 				$hfh=IO::File->new(">>$proname.hist")
                   2358: 				) { print $hfh "P:$now:$what\n"; }
                   2359: 			}
                   2360: 			my @pairs=split(/\&/,$what);
                   2361: 			my %hash;
                   2362: 			if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_WRCREAT(),0640)) {
                   2363: 			    foreach my $pair (@pairs) {
                   2364: 				my ($key,$value)=split(/=/,$pair);
                   2365: 				$hash{$key}=$value;
                   2366: 			    }
                   2367: 			    if (untie(%hash)) {
                   2368: 				print $client "ok\n";
                   2369: 			    } else {
                   2370: 				print $client "error: ".($!+0)
                   2371: 				    ." untie(GDBM) Failed ".
                   2372: 				    "while attempting idput\n";
                   2373: 			    }
                   2374: 			} else {
                   2375: 			    print $client "error: ".($!+0)
                   2376: 				." tie(GDBM) Failed ".
                   2377: 				"while attempting idput\n";
                   2378: 			}
                   2379: 		    } else {
                   2380: 			Reply($client, "refused\n", $userinput);
                   2381: 		       
                   2382: 		    }
1.1       albertel 2383: # ----------------------------------------------------------------------- idget
1.161     foxr     2384: 		} elsif ($userinput =~ /^idget/) {
                   2385: 		    if(isClient) {
                   2386: 			my ($cmd,$udom,$what)=split(/:/,$userinput);
                   2387: 			chomp($what);
                   2388: 			$udom=~s/\W//g;
                   2389: 			my $proname="$perlvar{'lonUsersDir'}/$udom/ids";
                   2390: 			my @queries=split(/\&/,$what);
                   2391: 			my $qresult='';
                   2392: 			my %hash;
                   2393: 			if (tie(%hash,'GDBM_File',"$proname.db",&GDBM_READER(),0640)) {
                   2394: 			    for (my $i=0;$i<=$#queries;$i++) {
                   2395: 				$qresult.="$hash{$queries[$i]}&";
                   2396: 			    }
                   2397: 			    if (untie(%hash)) {
                   2398: 				$qresult=~s/\&$//;
                   2399: 				print $client "$qresult\n";
                   2400: 			    } else {
                   2401: 				print $client "error: ".($!+0)
                   2402: 				    ." untie(GDBM) Failed ".
                   2403: 				    "while attempting idget\n";
                   2404: 			    }
                   2405: 			} else {
                   2406: 			    print $client "error: ".($!+0)
                   2407: 				." tie(GDBM) Failed ".
                   2408: 				"while attempting idget\n";
                   2409: 			}
                   2410: 		    } else {
                   2411: 			Reply($client, "refused\n", $userinput);
                   2412: 		       
                   2413: 		    }
1.13      www      2414: # ---------------------------------------------------------------------- tmpput
1.161     foxr     2415: 		} elsif ($userinput =~ /^tmpput/) {
                   2416: 		    if(isClient) {
                   2417: 			my ($cmd,$what)=split(/:/,$userinput);
                   2418: 			my $store;
                   2419: 			$tmpsnum++;
                   2420: 			my $id=$$.'_'.$clientip.'_'.$tmpsnum;
                   2421: 			$id=~s/\W/\_/g;
                   2422: 			$what=~s/\n//g;
                   2423: 			my $execdir=$perlvar{'lonDaemons'};
                   2424: 			if ($store=IO::File->new(">$execdir/tmp/$id.tmp")) {
                   2425: 			    print $store $what;
                   2426: 			    close $store;
                   2427: 			    print $client "$id\n";
                   2428: 			}
                   2429: 			else {
                   2430: 			    print $client "error: ".($!+0)
                   2431: 				."IO::File->new Failed ".
                   2432: 				"while attempting tmpput\n";
                   2433: 			}
                   2434: 		    } else {
                   2435: 			Reply($client, "refused\n", $userinput);
                   2436: 		    
                   2437: 		    }
                   2438: 		    
1.13      www      2439: # ---------------------------------------------------------------------- tmpget
1.161     foxr     2440: 		} elsif ($userinput =~ /^tmpget/) {
                   2441: 		    if(isClient) {
                   2442: 			my ($cmd,$id)=split(/:/,$userinput);
                   2443: 			chomp($id);
                   2444: 			$id=~s/\W/\_/g;
                   2445: 			my $store;
                   2446: 			my $execdir=$perlvar{'lonDaemons'};
                   2447: 			if ($store=IO::File->new("$execdir/tmp/$id.tmp")) {
                   2448: 			    my $reply=<$store>;
                   2449: 			    print $client "$reply\n";
                   2450: 			    close $store;
                   2451: 			}
                   2452: 			else {
                   2453: 			    print $client "error: ".($!+0)
                   2454: 				."IO::File->new Failed ".
                   2455: 				"while attempting tmpget\n";
                   2456: 			}
                   2457: 		    } else {
                   2458: 			Reply($client, "refused\n", $userinput);
                   2459: 		      
                   2460: 		    }
1.110     www      2461: # ---------------------------------------------------------------------- tmpdel
1.161     foxr     2462: 		} elsif ($userinput =~ /^tmpdel/) {
                   2463: 		    if(isClient) {
                   2464: 			my ($cmd,$id)=split(/:/,$userinput);
                   2465: 			chomp($id);
                   2466: 			$id=~s/\W/\_/g;
                   2467: 			my $execdir=$perlvar{'lonDaemons'};
                   2468: 			if (unlink("$execdir/tmp/$id.tmp")) {
                   2469: 			    print $client "ok\n";
                   2470: 			} else {
                   2471: 			    print $client "error: ".($!+0)
                   2472: 				."Unlink tmp Failed ".
                   2473: 				"while attempting tmpdel\n";
                   2474: 			}
                   2475: 		    } else {
                   2476: 			Reply($client, "refused\n", $userinput);
                   2477: 		     
                   2478: 		    }
1.5       www      2479: # -------------------------------------------------------------------------- ls
1.161     foxr     2480: 		} elsif ($userinput =~ /^ls/) {
                   2481: 		    if(isClient) {
                   2482: 			my ($cmd,$ulsdir)=split(/:/,$userinput);
                   2483: 			my $ulsout='';
                   2484: 			my $ulsfn;
                   2485: 			if (-e $ulsdir) {
                   2486: 			    if(-d $ulsdir) {
                   2487: 				if (opendir(LSDIR,$ulsdir)) {
                   2488: 				    while ($ulsfn=readdir(LSDIR)) {
                   2489: 					my @ulsstats=stat($ulsdir.'/'.$ulsfn);
                   2490: 					$ulsout.=$ulsfn.'&'.
                   2491: 					    join('&',@ulsstats).':';
                   2492: 				    }
                   2493: 				    closedir(LSDIR);
                   2494: 				}
                   2495: 			    } else {
                   2496: 				my @ulsstats=stat($ulsdir);
                   2497: 				$ulsout.=$ulsfn.'&'.join('&',@ulsstats).':';
                   2498: 			    }
                   2499: 			} else {
                   2500: 			    $ulsout='no_such_dir';
                   2501: 			}
                   2502: 			if ($ulsout eq '') { $ulsout='empty'; }
                   2503: 			print $client "$ulsout\n";
                   2504: 		    } else {
                   2505: 			Reply($client, "refused\n", $userinput);
                   2506: 		     
                   2507: 		    }
1.136     www      2508: # ----------------------------------------------------------------- setannounce
1.161     foxr     2509: 		} elsif ($userinput =~ /^setannounce/) {
                   2510: 		    if (isClient) {
                   2511: 			my ($cmd,$announcement)=split(/:/,$userinput);
                   2512: 			chomp($announcement);
                   2513: 			$announcement=&unescape($announcement);
                   2514: 			if (my $store=IO::File->new('>'.$perlvar{'lonDocRoot'}.
                   2515: 						    '/announcement.txt')) {
                   2516: 			    print $store $announcement;
                   2517: 			    close $store;
                   2518: 			    print $client "ok\n";
                   2519: 			} else {
                   2520: 			    print $client "error: ".($!+0)."\n";
                   2521: 			}
                   2522: 		    } else {
                   2523: 			Reply($client, "refused\n", $userinput);
                   2524: 		       
                   2525: 		    }
1.51      www      2526: # ------------------------------------------------------------------ Hanging up
1.161     foxr     2527: 		} elsif (($userinput =~ /^exit/) ||
                   2528: 			 ($userinput =~ /^init/)) { # no restrictions.
                   2529: 		    &logthis(
                   2530: 			     "Client $clientip ($clientname) hanging up: $userinput");
                   2531: 		    print $client "bye\n";
1.164     foxr     2532: 		    $client->shutdown(2);        # shutdown the socket forcibly.
1.161     foxr     2533: 		    $client->close();
                   2534: 		    last;
                   2535: 
                   2536: # ---------------------------------- set current host/domain
                   2537: 		} elsif ($userinput =~ /^sethost:/) {
                   2538: 		    if (isClient) {
                   2539: 			print $client &sethost($userinput)."\n";
                   2540: 		    } else {
                   2541: 			print $client "refused\n";
                   2542: 		    }
                   2543: #---------------------------------- request file (?) version.
                   2544: 		} elsif ($userinput =~/^version:/) {
                   2545: 		    if (isClient) {
                   2546: 			print $client &version($userinput)."\n";
                   2547: 		    } else {
                   2548: 			print $client "refused\n";
                   2549: 		    }
1.1       albertel 2550: # ------------------------------------------------------------- unknown command
1.161     foxr     2551: 
                   2552: 		} else {
                   2553: 		    # unknown command
                   2554: 		    print $client "unknown_cmd\n";
                   2555: 		}
1.58      www      2556: # -------------------------------------------------------------------- complete
1.161     foxr     2557: 		alarm(0);
                   2558: 		&status('Listening to '.$clientname);
                   2559: 	    }
1.59      www      2560: # --------------------------------------------- client unknown or fishy, refuse
1.161     foxr     2561: 	} else {
                   2562: 	    print $client "refused\n";
                   2563: 	    $client->close();
                   2564: 	    &logthis("<font color=blue>WARNING: "
                   2565: 		     ."Rejected client $clientip, closing connection</font>");
                   2566: 	}
                   2567:     }             
                   2568:     
1.1       albertel 2569: # =============================================================================
1.161     foxr     2570:     
                   2571:     &logthis("<font color=red>CRITICAL: "
                   2572: 	     ."Disconnect from $clientip ($clientname)</font>");    
                   2573:     
                   2574:     
                   2575:     # this exit is VERY important, otherwise the child will become
                   2576:     # a producer of more and more children, forking yourself into
                   2577:     # process death.
                   2578:     exit;
1.106     foxr     2579:     
1.78      foxr     2580: }
                   2581: 
                   2582: 
                   2583: #
                   2584: #   Checks to see if the input roleput request was to set
                   2585: # an author role.  If so, invokes the lchtmldir script to set
                   2586: # up a correct public_html 
                   2587: # Parameters:
                   2588: #    request   - The request sent to the rolesput subchunk.
                   2589: #                We're looking for  /domain/_au
                   2590: #    domain    - The domain in which the user is having roles doctored.
                   2591: #    user      - Name of the user for which the role is being put.
                   2592: #    authtype  - The authentication type associated with the user.
                   2593: #
                   2594: sub ManagePermissions
                   2595: {
                   2596:     my $request = shift;
                   2597:     my $domain  = shift;
                   2598:     my $user    = shift;
                   2599:     my $authtype= shift;
                   2600: 
                   2601:     # See if the request is of the form /$domain/_au
1.134     albertel 2602:     &logthis("ruequest is $request");
1.78      foxr     2603:     if($request =~ /^(\/$domain\/_au)$/) { # It's an author rolesput...
                   2604: 	my $execdir = $perlvar{'lonDaemons'};
                   2605: 	my $userhome= "/home/$user" ;
1.134     albertel 2606: 	&logthis("system $execdir/lchtmldir $userhome $user $authtype");
1.78      foxr     2607: 	system("$execdir/lchtmldir $userhome $user $authtype");
                   2608:     }
                   2609: }
                   2610: #
                   2611: #   GetAuthType - Determines the authorization type of a user in a domain.
                   2612: 
                   2613: #     Returns the authorization type or nouser if there is no such user.
                   2614: #
                   2615: sub GetAuthType 
                   2616: {
                   2617:     my $domain = shift;
                   2618:     my $user   = shift;
                   2619: 
1.79      foxr     2620:     Debug("GetAuthType( $domain, $user ) \n");
1.78      foxr     2621:     my $proname    = &propath($domain, $user); 
                   2622:     my $passwdfile = "$proname/passwd";
                   2623:     if( -e $passwdfile ) {
                   2624: 	my $pf = IO::File->new($passwdfile);
                   2625: 	my $realpassword = <$pf>;
                   2626: 	chomp($realpassword);
1.79      foxr     2627: 	Debug("Password info = $realpassword\n");
1.78      foxr     2628: 	my ($authtype, $contentpwd) = split(/:/, $realpassword);
1.79      foxr     2629: 	Debug("Authtype = $authtype, content = $contentpwd\n");
1.78      foxr     2630: 	my $availinfo = '';
1.91      albertel 2631: 	if($authtype eq 'krb4' or $authtype eq 'krb5') {
1.78      foxr     2632: 	    $availinfo = $contentpwd;
                   2633: 	}
1.79      foxr     2634: 
1.78      foxr     2635: 	return "$authtype:$availinfo";
                   2636:     }
                   2637:     else {
1.79      foxr     2638: 	Debug("Returning nouser");
1.78      foxr     2639: 	return "nouser";
                   2640:     }
1.1       albertel 2641: }
                   2642: 
1.84      albertel 2643: sub addline {
                   2644:     my ($fname,$hostid,$ip,$newline)=@_;
                   2645:     my $contents;
                   2646:     my $found=0;
                   2647:     my $expr='^'.$hostid.':'.$ip.':';
                   2648:     $expr =~ s/\./\\\./g;
1.134     albertel 2649:     my $sh;
1.84      albertel 2650:     if ($sh=IO::File->new("$fname.subscription")) {
                   2651: 	while (my $subline=<$sh>) {
                   2652: 	    if ($subline !~ /$expr/) {$contents.= $subline;} else {$found=1;}
                   2653: 	}
                   2654: 	$sh->close();
                   2655:     }
                   2656:     $sh=IO::File->new(">$fname.subscription");
                   2657:     if ($contents) { print $sh $contents; }
                   2658:     if ($newline) { print $sh $newline; }
                   2659:     $sh->close();
                   2660:     return $found;
1.86      www      2661: }
                   2662: 
                   2663: sub getchat {
1.122     www      2664:     my ($cdom,$cname,$udom,$uname)=@_;
1.87      www      2665:     my %hash;
                   2666:     my $proname=&propath($cdom,$cname);
                   2667:     my @entries=();
1.88      albertel 2668:     if (tie(%hash,'GDBM_File',"$proname/nohist_chatroom.db",
                   2669: 	    &GDBM_READER(),0640)) {
                   2670: 	@entries=map { $_.':'.$hash{$_} } sort keys %hash;
                   2671: 	untie %hash;
1.123     www      2672:     }
1.124     www      2673:     my @participants=();
1.134     albertel 2674:     my $cutoff=time-60;
1.123     www      2675:     if (tie(%hash,'GDBM_File',"$proname/nohist_inchatroom.db",
1.124     www      2676: 	    &GDBM_WRCREAT(),0640)) {
                   2677:         $hash{$uname.':'.$udom}=time;
1.123     www      2678:         foreach (sort keys %hash) {
                   2679: 	    if ($hash{$_}>$cutoff) {
1.124     www      2680: 		$participants[$#participants+1]='active_participant:'.$_;
1.123     www      2681:             }
                   2682:         }
                   2683:         untie %hash;
1.86      www      2684:     }
1.124     www      2685:     return (@participants,@entries);
1.86      www      2686: }
                   2687: 
                   2688: sub chatadd {
1.88      albertel 2689:     my ($cdom,$cname,$newchat)=@_;
                   2690:     my %hash;
                   2691:     my $proname=&propath($cdom,$cname);
                   2692:     my @entries=();
1.142     www      2693:     my $time=time;
1.88      albertel 2694:     if (tie(%hash,'GDBM_File',"$proname/nohist_chatroom.db",
                   2695: 	    &GDBM_WRCREAT(),0640)) {
                   2696: 	@entries=map { $_.':'.$hash{$_} } sort keys %hash;
                   2697: 	my ($lastid)=($entries[$#entries]=~/^(\w+)\:/);
                   2698: 	my ($thentime,$idnum)=split(/\_/,$lastid);
                   2699: 	my $newid=$time.'_000000';
                   2700: 	if ($thentime==$time) {
                   2701: 	    $idnum=~s/^0+//;
                   2702: 	    $idnum++;
                   2703: 	    $idnum=substr('000000'.$idnum,-6,6);
                   2704: 	    $newid=$time.'_'.$idnum;
                   2705: 	}
                   2706: 	$hash{$newid}=$newchat;
                   2707: 	my $expired=$time-3600;
                   2708: 	foreach (keys %hash) {
                   2709: 	    my ($thistime)=($_=~/(\d+)\_/);
                   2710: 	    if ($thistime<$expired) {
1.89      www      2711: 		delete $hash{$_};
1.88      albertel 2712: 	    }
                   2713: 	}
                   2714: 	untie %hash;
1.142     www      2715:     }
                   2716:     {
                   2717: 	my $hfh;
                   2718: 	if ($hfh=IO::File->new(">>$proname/chatroom.log")) { 
                   2719: 	    print $hfh "$time:".&unescape($newchat)."\n";
                   2720: 	}
1.86      www      2721:     }
1.84      albertel 2722: }
                   2723: 
                   2724: sub unsub {
                   2725:     my ($fname,$clientip)=@_;
                   2726:     my $result;
1.161     foxr     2727:     if (unlink("$fname.$clientname")) {
1.84      albertel 2728: 	$result="ok\n";
                   2729:     } else {
                   2730: 	$result="not_subscribed\n";
                   2731:     }
                   2732:     if (-e "$fname.subscription") {
1.161     foxr     2733: 	my $found=&addline($fname,$clientname,$clientip,'');
1.84      albertel 2734: 	if ($found) { $result="ok\n"; }
                   2735:     } else {
                   2736: 	if ($result != "ok\n") { $result="not_subscribed\n"; }
                   2737:     }
                   2738:     return $result;
                   2739: }
                   2740: 
1.101     www      2741: sub currentversion {
                   2742:     my $fname=shift;
                   2743:     my $version=-1;
                   2744:     my $ulsdir='';
                   2745:     if ($fname=~/^(.+)\/[^\/]+$/) {
                   2746:        $ulsdir=$1;
                   2747:     }
1.114     albertel 2748:     my ($fnamere1,$fnamere2);
                   2749:     # remove version if already specified
1.101     www      2750:     $fname=~s/\.\d+\.(\w+(?:\.meta)*)$/\.$1/;
1.114     albertel 2751:     # get the bits that go before and after the version number
                   2752:     if ( $fname=~/^(.*\.)(\w+(?:\.meta)*)$/ ) {
                   2753: 	$fnamere1=$1;
                   2754: 	$fnamere2='.'.$2;
                   2755:     }
1.101     www      2756:     if (-e $fname) { $version=1; }
                   2757:     if (-e $ulsdir) {
1.134     albertel 2758: 	if(-d $ulsdir) {
                   2759: 	    if (opendir(LSDIR,$ulsdir)) {
                   2760: 		my $ulsfn;
                   2761: 		while ($ulsfn=readdir(LSDIR)) {
1.101     www      2762: # see if this is a regular file (ignore links produced earlier)
1.134     albertel 2763: 		    my $thisfile=$ulsdir.'/'.$ulsfn;
                   2764: 		    unless (-l $thisfile) {
1.160     www      2765: 			if ($thisfile=~/\Q$fnamere1\E(\d+)\Q$fnamere2\E$/) {
1.134     albertel 2766: 			    if ($1>$version) { $version=$1; }
                   2767: 			}
                   2768: 		    }
                   2769: 		}
                   2770: 		closedir(LSDIR);
                   2771: 		$version++;
                   2772: 	    }
                   2773: 	}
                   2774:     }
                   2775:     return $version;
1.101     www      2776: }
                   2777: 
                   2778: sub thisversion {
                   2779:     my $fname=shift;
                   2780:     my $version=-1;
                   2781:     if ($fname=~/\.(\d+)\.\w+(?:\.meta)*$/) {
                   2782: 	$version=$1;
                   2783:     }
                   2784:     return $version;
                   2785: }
                   2786: 
1.84      albertel 2787: sub subscribe {
                   2788:     my ($userinput,$clientip)=@_;
                   2789:     my $result;
                   2790:     my ($cmd,$fname)=split(/:/,$userinput);
                   2791:     my $ownership=&ishome($fname);
                   2792:     if ($ownership eq 'owner') {
1.101     www      2793: # explitly asking for the current version?
                   2794:         unless (-e $fname) {
                   2795:             my $currentversion=&currentversion($fname);
                   2796: 	    if (&thisversion($fname)==$currentversion) {
                   2797:                 if ($fname=~/^(.+)\.\d+\.(\w+(?:\.meta)*)$/) {
                   2798: 		    my $root=$1;
                   2799:                     my $extension=$2;
                   2800:                     symlink($root.'.'.$extension,
                   2801:                             $root.'.'.$currentversion.'.'.$extension);
1.102     www      2802:                     unless ($extension=~/\.meta$/) {
                   2803:                        symlink($root.'.'.$extension.'.meta',
                   2804:                             $root.'.'.$currentversion.'.'.$extension.'.meta');
                   2805: 		    }
1.101     www      2806:                 }
                   2807:             }
                   2808:         }
1.84      albertel 2809: 	if (-e $fname) {
                   2810: 	    if (-d $fname) {
                   2811: 		$result="directory\n";
                   2812: 	    } else {
1.161     foxr     2813: 		if (-e "$fname.$clientname") {&unsub($fname,$clientip);}
1.134     albertel 2814: 		my $now=time;
1.161     foxr     2815: 		my $found=&addline($fname,$clientname,$clientip,
                   2816: 				   "$clientname:$clientip:$now\n");
1.84      albertel 2817: 		if ($found) { $result="$fname\n"; }
                   2818: 		# if they were subscribed to only meta data, delete that
                   2819:                 # subscription, when you subscribe to a file you also get
                   2820:                 # the metadata
                   2821: 		unless ($fname=~/\.meta$/) { &unsub("$fname.meta",$clientip); }
                   2822: 		$fname=~s/\/home\/httpd\/html\/res/raw/;
                   2823: 		$fname="http://$thisserver/".$fname;
                   2824: 		$result="$fname\n";
                   2825: 	    }
                   2826: 	} else {
                   2827: 	    $result="not_found\n";
                   2828: 	}
                   2829:     } else {
                   2830: 	$result="rejected\n";
                   2831:     }
                   2832:     return $result;
                   2833: }
1.91      albertel 2834: 
                   2835: sub make_passwd_file {
1.98      foxr     2836:     my ($uname, $umode,$npass,$passfilename)=@_;
1.91      albertel 2837:     my $result="ok\n";
                   2838:     if ($umode eq 'krb4' or $umode eq 'krb5') {
                   2839: 	{
                   2840: 	    my $pf = IO::File->new(">$passfilename");
                   2841: 	    print $pf "$umode:$npass\n";
                   2842: 	}
                   2843:     } elsif ($umode eq 'internal') {
                   2844: 	my $salt=time;
                   2845: 	$salt=substr($salt,6,2);
                   2846: 	my $ncpass=crypt($npass,$salt);
                   2847: 	{
                   2848: 	    &Debug("Creating internal auth");
                   2849: 	    my $pf = IO::File->new(">$passfilename");
                   2850: 	    print $pf "internal:$ncpass\n"; 
                   2851: 	}
                   2852:     } elsif ($umode eq 'localauth') {
                   2853: 	{
                   2854: 	    my $pf = IO::File->new(">$passfilename");
                   2855: 	    print $pf "localauth:$npass\n";
                   2856: 	}
                   2857:     } elsif ($umode eq 'unix') {
                   2858: 	{
1.165.2.4! albertel 2859: 	    #
        !          2860: 	    #  Don't allow the creation of privileged accounts!!! that would
        !          2861: 	    #  be real bad!!!
        !          2862: 	    #
        !          2863: 	    my $uid = getpwnam($uname);
        !          2864: 	    if((defined $uid) && ($uid == 0)) {
        !          2865: 		&logthis(">>>Attempted to create privilged account blocked");
        !          2866: 		return "no_priv_account_error\n";
        !          2867: 	    }
        !          2868: 
1.91      albertel 2869: 	    my $execpath="$perlvar{'lonDaemons'}/"."lcuseradd";
                   2870: 	    {
                   2871: 		&Debug("Executing external: ".$execpath);
1.98      foxr     2872: 		&Debug("user  = ".$uname.", Password =". $npass);
1.132     matthew  2873: 		my $se = IO::File->new("|$execpath > $perlvar{'lonDaemons'}/logs/lcuseradd.log");
1.91      albertel 2874: 		print $se "$uname\n";
                   2875: 		print $se "$npass\n";
                   2876: 		print $se "$npass\n";
1.97      foxr     2877: 	    }
                   2878: 	    my $useraddok = $?;
                   2879: 	    if($useraddok > 0) {
                   2880: 		&logthis("Failed lcuseradd: ".&lcuseraddstrerror($useraddok));
1.91      albertel 2881: 	    }
                   2882: 	    my $pf = IO::File->new(">$passfilename");
                   2883: 	    print $pf "unix:\n";
                   2884: 	}
                   2885:     } elsif ($umode eq 'none') {
                   2886: 	{
                   2887: 	    my $pf = IO::File->new(">$passfilename");
                   2888: 	    print $pf "none:\n";
                   2889: 	}
                   2890:     } else {
                   2891: 	$result="auth_mode_error\n";
                   2892:     }
                   2893:     return $result;
1.121     albertel 2894: }
                   2895: 
                   2896: sub sethost {
                   2897:     my ($remotereq) = @_;
                   2898:     my (undef,$hostid)=split(/:/,$remotereq);
                   2899:     if (!defined($hostid)) { $hostid=$perlvar{'lonHostID'}; }
                   2900:     if ($hostip{$perlvar{'lonHostID'}} eq $hostip{$hostid}) {
                   2901: 	$currenthostid=$hostid;
                   2902: 	$currentdomainid=$hostdom{$hostid};
                   2903: 	&logthis("Setting hostid to $hostid, and domain to $currentdomainid");
                   2904:     } else {
                   2905: 	&logthis("Requested host id $hostid not an alias of ".
                   2906: 		 $perlvar{'lonHostID'}." refusing connection");
                   2907: 	return 'unable_to_set';
                   2908:     }
                   2909:     return 'ok';
                   2910: }
                   2911: 
                   2912: sub version {
                   2913:     my ($userinput)=@_;
                   2914:     $remoteVERSION=(split(/:/,$userinput))[1];
                   2915:     return "version:$VERSION";
1.127     albertel 2916: }
                   2917: 
1.128     albertel 2918: #There is a copy of this in lonnet.pm
1.127     albertel 2919: sub userload {
                   2920:     my $numusers=0;
                   2921:     {
                   2922: 	opendir(LONIDS,$perlvar{'lonIDsDir'});
                   2923: 	my $filename;
                   2924: 	my $curtime=time;
                   2925: 	while ($filename=readdir(LONIDS)) {
                   2926: 	    if ($filename eq '.' || $filename eq '..') {next;}
1.138     albertel 2927: 	    my ($mtime)=(stat($perlvar{'lonIDsDir'}.'/'.$filename))[9];
1.159     albertel 2928: 	    if ($curtime-$mtime < 1800) { $numusers++; }
1.127     albertel 2929: 	}
                   2930: 	closedir(LONIDS);
                   2931:     }
                   2932:     my $userloadpercent=0;
                   2933:     my $maxuserload=$perlvar{'lonUserLoadLim'};
                   2934:     if ($maxuserload) {
1.129     albertel 2935: 	$userloadpercent=100*$numusers/$maxuserload;
1.127     albertel 2936:     }
1.130     albertel 2937:     $userloadpercent=sprintf("%.2f",$userloadpercent);
1.127     albertel 2938:     return $userloadpercent;
1.91      albertel 2939: }
                   2940: 
1.61      harris41 2941: # ----------------------------------- POD (plain old documentation, CPAN style)
                   2942: 
                   2943: =head1 NAME
                   2944: 
                   2945: lond - "LON Daemon" Server (port "LOND" 5663)
                   2946: 
                   2947: =head1 SYNOPSIS
                   2948: 
1.74      harris41 2949: Usage: B<lond>
                   2950: 
                   2951: Should only be run as user=www.  This is a command-line script which
                   2952: is invoked by B<loncron>.  There is no expectation that a typical user
                   2953: will manually start B<lond> from the command-line.  (In other words,
                   2954: DO NOT START B<lond> YOURSELF.)
1.61      harris41 2955: 
                   2956: =head1 DESCRIPTION
                   2957: 
1.74      harris41 2958: There are two characteristics associated with the running of B<lond>,
                   2959: PROCESS MANAGEMENT (starting, stopping, handling child processes)
                   2960: and SERVER-SIDE ACTIVITIES (password authentication, user creation,
                   2961: subscriptions, etc).  These are described in two large
                   2962: sections below.
                   2963: 
                   2964: B<PROCESS MANAGEMENT>
                   2965: 
1.61      harris41 2966: Preforker - server who forks first. Runs as a daemon. HUPs.
                   2967: Uses IDEA encryption
                   2968: 
1.74      harris41 2969: B<lond> forks off children processes that correspond to the other servers
                   2970: in the network.  Management of these processes can be done at the
                   2971: parent process level or the child process level.
                   2972: 
                   2973: B<logs/lond.log> is the location of log messages.
                   2974: 
                   2975: The process management is now explained in terms of linux shell commands,
                   2976: subroutines internal to this code, and signal assignments:
                   2977: 
                   2978: =over 4
                   2979: 
                   2980: =item *
                   2981: 
                   2982: PID is stored in B<logs/lond.pid>
                   2983: 
                   2984: This is the process id number of the parent B<lond> process.
                   2985: 
                   2986: =item *
                   2987: 
                   2988: SIGTERM and SIGINT
                   2989: 
                   2990: Parent signal assignment:
                   2991:  $SIG{INT}  = $SIG{TERM} = \&HUNTSMAN;
                   2992: 
                   2993: Child signal assignment:
                   2994:  $SIG{INT}  = 'DEFAULT'; (and SIGTERM is DEFAULT also)
                   2995: (The child dies and a SIGALRM is sent to parent, awaking parent from slumber
                   2996:  to restart a new child.)
                   2997: 
                   2998: Command-line invocations:
                   2999:  B<kill> B<-s> SIGTERM I<PID>
                   3000:  B<kill> B<-s> SIGINT I<PID>
                   3001: 
                   3002: Subroutine B<HUNTSMAN>:
                   3003:  This is only invoked for the B<lond> parent I<PID>.
                   3004: This kills all the children, and then the parent.
                   3005: The B<lonc.pid> file is cleared.
                   3006: 
                   3007: =item *
                   3008: 
                   3009: SIGHUP
                   3010: 
                   3011: Current bug:
                   3012:  This signal can only be processed the first time
                   3013: on the parent process.  Subsequent SIGHUP signals
                   3014: have no effect.
                   3015: 
                   3016: Parent signal assignment:
                   3017:  $SIG{HUP}  = \&HUPSMAN;
                   3018: 
                   3019: Child signal assignment:
                   3020:  none (nothing happens)
                   3021: 
                   3022: Command-line invocations:
                   3023:  B<kill> B<-s> SIGHUP I<PID>
                   3024: 
                   3025: Subroutine B<HUPSMAN>:
                   3026:  This is only invoked for the B<lond> parent I<PID>,
                   3027: This kills all the children, and then the parent.
                   3028: The B<lond.pid> file is cleared.
                   3029: 
                   3030: =item *
                   3031: 
                   3032: SIGUSR1
                   3033: 
                   3034: Parent signal assignment:
                   3035:  $SIG{USR1} = \&USRMAN;
                   3036: 
                   3037: Child signal assignment:
                   3038:  $SIG{USR1}= \&logstatus;
                   3039: 
                   3040: Command-line invocations:
                   3041:  B<kill> B<-s> SIGUSR1 I<PID>
                   3042: 
                   3043: Subroutine B<USRMAN>:
                   3044:  When invoked for the B<lond> parent I<PID>,
                   3045: SIGUSR1 is sent to all the children, and the status of
                   3046: each connection is logged.
1.144     foxr     3047: 
                   3048: =item *
                   3049: 
                   3050: SIGUSR2
                   3051: 
                   3052: Parent Signal assignment:
                   3053:     $SIG{USR2} = \&UpdateHosts
                   3054: 
                   3055: Child signal assignment:
                   3056:     NONE
                   3057: 
1.74      harris41 3058: 
                   3059: =item *
                   3060: 
                   3061: SIGCHLD
                   3062: 
                   3063: Parent signal assignment:
                   3064:  $SIG{CHLD} = \&REAPER;
                   3065: 
                   3066: Child signal assignment:
                   3067:  none
                   3068: 
                   3069: Command-line invocations:
                   3070:  B<kill> B<-s> SIGCHLD I<PID>
                   3071: 
                   3072: Subroutine B<REAPER>:
                   3073:  This is only invoked for the B<lond> parent I<PID>.
                   3074: Information pertaining to the child is removed.
                   3075: The socket port is cleaned up.
                   3076: 
                   3077: =back
                   3078: 
                   3079: B<SERVER-SIDE ACTIVITIES>
                   3080: 
                   3081: Server-side information can be accepted in an encrypted or non-encrypted
                   3082: method.
                   3083: 
                   3084: =over 4
                   3085: 
                   3086: =item ping
                   3087: 
                   3088: Query a client in the hosts.tab table; "Are you there?"
                   3089: 
                   3090: =item pong
                   3091: 
                   3092: Respond to a ping query.
                   3093: 
                   3094: =item ekey
                   3095: 
                   3096: Read in encrypted key, make cipher.  Respond with a buildkey.
                   3097: 
                   3098: =item load
                   3099: 
                   3100: Respond with CPU load based on a computation upon /proc/loadavg.
                   3101: 
                   3102: =item currentauth
                   3103: 
                   3104: Reply with current authentication information (only over an
                   3105: encrypted channel).
                   3106: 
                   3107: =item auth
                   3108: 
                   3109: Only over an encrypted channel, reply as to whether a user's
                   3110: authentication information can be validated.
                   3111: 
                   3112: =item passwd
                   3113: 
                   3114: Allow for a password to be set.
                   3115: 
                   3116: =item makeuser
                   3117: 
                   3118: Make a user.
                   3119: 
                   3120: =item passwd
                   3121: 
                   3122: Allow for authentication mechanism and password to be changed.
                   3123: 
                   3124: =item home
1.61      harris41 3125: 
1.74      harris41 3126: Respond to a question "are you the home for a given user?"
                   3127: 
                   3128: =item update
                   3129: 
                   3130: Update contents of a subscribed resource.
                   3131: 
                   3132: =item unsubscribe
                   3133: 
                   3134: The server is unsubscribing from a resource.
                   3135: 
                   3136: =item subscribe
                   3137: 
                   3138: The server is subscribing to a resource.
                   3139: 
                   3140: =item log
                   3141: 
                   3142: Place in B<logs/lond.log>
                   3143: 
                   3144: =item put
                   3145: 
                   3146: stores hash in namespace
                   3147: 
                   3148: =item rolesput
                   3149: 
                   3150: put a role into a user's environment
                   3151: 
                   3152: =item get
                   3153: 
                   3154: returns hash with keys from array
                   3155: reference filled in from namespace
                   3156: 
                   3157: =item eget
                   3158: 
                   3159: returns hash with keys from array
                   3160: reference filled in from namesp (encrypts the return communication)
                   3161: 
                   3162: =item rolesget
                   3163: 
                   3164: get a role from a user's environment
                   3165: 
                   3166: =item del
                   3167: 
                   3168: deletes keys out of array from namespace
                   3169: 
                   3170: =item keys
                   3171: 
                   3172: returns namespace keys
                   3173: 
                   3174: =item dump
                   3175: 
                   3176: dumps the complete (or key matching regexp) namespace into a hash
                   3177: 
                   3178: =item store
                   3179: 
                   3180: stores hash permanently
                   3181: for this url; hashref needs to be given and should be a \%hashname; the
                   3182: remaining args aren't required and if they aren't passed or are '' they will
                   3183: be derived from the ENV
                   3184: 
                   3185: =item restore
                   3186: 
                   3187: returns a hash for a given url
                   3188: 
                   3189: =item querysend
                   3190: 
                   3191: Tells client about the lonsql process that has been launched in response
                   3192: to a sent query.
                   3193: 
                   3194: =item queryreply
                   3195: 
                   3196: Accept information from lonsql and make appropriate storage in temporary
                   3197: file space.
                   3198: 
                   3199: =item idput
                   3200: 
                   3201: Defines usernames as corresponding to IDs.  (These "IDs" are unique identifiers
                   3202: for each student, defined perhaps by the institutional Registrar.)
                   3203: 
                   3204: =item idget
                   3205: 
                   3206: Returns usernames corresponding to IDs.  (These "IDs" are unique identifiers
                   3207: for each student, defined perhaps by the institutional Registrar.)
                   3208: 
                   3209: =item tmpput
                   3210: 
                   3211: Accept and store information in temporary space.
                   3212: 
                   3213: =item tmpget
                   3214: 
                   3215: Send along temporarily stored information.
                   3216: 
                   3217: =item ls
                   3218: 
                   3219: List part of a user's directory.
                   3220: 
1.135     foxr     3221: =item pushtable
                   3222: 
                   3223: Pushes a file in /home/httpd/lonTab directory.  Currently limited to:
                   3224: hosts.tab and domain.tab. The old file is copied to  *.tab.backup but
                   3225: must be restored manually in case of a problem with the new table file.
                   3226: pushtable requires that the request be encrypted and validated via
                   3227: ValidateManager.  The form of the command is:
                   3228: enc:pushtable tablename <tablecontents> \n
                   3229: where pushtable, tablename and <tablecontents> will be encrypted, but \n is a 
                   3230: cleartext newline.
                   3231: 
1.74      harris41 3232: =item Hanging up (exit or init)
                   3233: 
                   3234: What to do when a client tells the server that they (the client)
                   3235: are leaving the network.
                   3236: 
                   3237: =item unknown command
                   3238: 
                   3239: If B<lond> is sent an unknown command (not in the list above),
                   3240: it replys to the client "unknown_cmd".
1.135     foxr     3241: 
1.74      harris41 3242: 
                   3243: =item UNKNOWN CLIENT
                   3244: 
                   3245: If the anti-spoofing algorithm cannot verify the client,
                   3246: the client is rejected (with a "refused" message sent
                   3247: to the client, and the connection is closed.
                   3248: 
                   3249: =back
1.61      harris41 3250: 
                   3251: =head1 PREREQUISITES
                   3252: 
                   3253: IO::Socket
                   3254: IO::File
                   3255: Apache::File
                   3256: Symbol
                   3257: POSIX
                   3258: Crypt::IDEA
                   3259: LWP::UserAgent()
                   3260: GDBM_File
                   3261: Authen::Krb4
1.91      albertel 3262: Authen::Krb5
1.61      harris41 3263: 
                   3264: =head1 COREQUISITES
                   3265: 
                   3266: =head1 OSNAMES
                   3267: 
                   3268: linux
                   3269: 
                   3270: =head1 SCRIPT CATEGORIES
                   3271: 
                   3272: Server/Process
                   3273: 
                   3274: =cut

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.