--- loncom/lond 2003/09/29 10:09:18 1.148 +++ loncom/lond 2003/10/21 09:14:31 1.158 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.148 2003/09/29 10:09:18 foxr Exp $ +# $Id: lond,v 1.158 2003/10/21 09:14:31 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -59,41 +59,12 @@ # - pushing /home/httpd/lonTabs/domain.tab # 09/08/2003 Ron Fox: Told lond to take care of change logging so we # don't have to remember it: -# $Log: lond,v $ -# Revision 1.148 2003/09/29 10:09:18 foxr -# Put in logic to reinit lond itself (except for apache reload). I don't believe -# this logic works correctly yet, however lond still does everything it used to doso I'll do the commit anyway. -# -# Revision 1.147 2003/09/23 11:23:31 foxr -# Comlplete implementation of reinit functionality. Must still implement -# the actual initialization functionality, but the process can now -# receive the request and either invoke the appropriate internal function or -# signal the correct lonc. -# -# Revision 1.146 2003/09/16 10:28:14 foxr -# ReinitProcess - decode the process selector and produce the associated pid -# filename. Note: While it is possible to test that valid process selectors are -# handled properly I am not able to test that invalid process selectors produce -# the appropriate error as lonManage also blocks the use of invalid process selectors. -# -# Revision 1.145 2003/09/16 10:13:20 foxr -# Added ReinitProcess function to oversee the parsing and processing of the -# reinit: client request. -# -# Revision 1.144 2003/09/16 09:47:01 foxr -# Added skeletal support for SIGUSR2 (update hosts.tab) -# -# Revision 1.143 2003/09/15 10:03:52 foxr -# Completed and tested code for pushfile. -# -# Revision 1.142 2003/09/09 20:47:46 www -# Permanently store chatroom entries in chatroom.log -# -# Revision 1.141 2003/09/08 10:32:07 foxr -# Added PushFile sub This sub oversees the push of a new configuration table file -# Currently supported files are: -# - hosts.tab (transaction pushfile:hosts:contents) -# - domain.tab (transaction pushfile:domain:contents) +# +# Change Log: +# $Log: lond,v $ +# Revision 1.158 2003/10/21 09:14:31 foxr +# Re-install $Log$ in comment header to support automatic change logging. +# # @@ -120,7 +91,7 @@ my $DEBUG = 0; # Non zero to ena my $status=''; my $lastlog=''; -my $VERSION='$Revision: 1.148 $'; #' stupid emacs +my $VERSION='$Revision: 1.158 $'; #' stupid emacs my $remoteVERSION; my $currenthostid; my $currentdomainid; @@ -134,6 +105,7 @@ my $thisserver; my %hostid; my %hostdom; my %hostip; +my %managers; # If defined $managers{hostname} is a manager my %perlvar; # Will have the apache conf defined perl vars. # @@ -164,10 +136,10 @@ my @adderrors = ("ok", "lcuseradd Incorrect number of stdinput lines, must be 3", "lcuseradd Too many other simultaneous pwd changes in progress", "lcuseradd User does not exist", - "lcuseradd Unabel to mak ewww member of users's group", + "lcuseradd Unable to make www member of users's group", "lcuseradd Unable to su to root", "lcuseradd Unable to set password", - "lcuseradd Usrname has invbalid charcters", + "lcuseradd Usrname has invalid characters", "lcuseradd Password has an invalid character", "lcuseradd User already exists", "lcuseradd Could not add user.", @@ -190,7 +162,37 @@ sub GetCertificate { return $clientip; } +# +# ReadManagerTable: Reads in the current manager table. For now this is +# done on each manager authentication because: +# - These authentications are not frequent +# - This allows dynamic changes to the manager table +# without the need to signal to the lond. +# + +sub ReadManagerTable { + + # Clean out the old table first.. + foreach my $key (keys %managers) { + delete $managers{$key}; + } + + my $tablename = $perlvar{'lonTabDir'}."/managers.tab"; + if (!open (MANAGERS, $tablename)) { + logthis('No manager table. Nobody can manage!!'); + return; + } + while(my $host = ) { + chomp($host); + if (!defined $hostip{$host}) { + logthis(' manager '.$host. + " not in hosts.tab, rejected as manager"); + } else { + $managers{$host} = $hostip{$host}; # Whatever for now. + } + } +} # # ValidManager: Determines if a given certificate represents a valid manager. @@ -202,14 +204,25 @@ sub GetCertificate { sub ValidManager { my $certificate = shift; - my $hostentry = $hostid{$certificate}; - if ($hostentry ne undef) { - &logthis('Authenticating manager'. - " $hostentry"); - return 1; + ReadManagerTable; + + my $hostname = $hostid{$certificate}; + + + if ($hostname ne undef) { + if($managers{$hostname} ne undef) { + &logthis('Authenticating manager'. + " $hostname"); + return 1; + } else { + &logthis('"); + return 0; + } } else { &logthis(' Failed manager authentication '. "$certificate "); + return 0; } } # @@ -261,7 +274,66 @@ sub CopyFile { return 0; } } - +# +# Host files are passed out with externally visible host IPs. +# If, for example, we are behind a fire-wall or NAT host, our +# internally visible IP may be different than the externally +# visible IP. Therefore, we always adjust the contents of the +# host file so that the entry for ME is the IP that we believe +# we have. At present, this is defined as the entry that +# DNS has for us. If by some chance we are not able to get a +# DNS translation for us, then we assume that the host.tab file +# is correct. +# BUGBUGBUG - in the future, we really should see if we can +# easily query the interface(s) instead. +# Parameter(s): +# contents - The contents of the host.tab to check. +# Returns: +# newcontents - The adjusted contents. +# +# +sub AdjustHostContents { + my $contents = shift; + my $adjusted; + my $me = $perlvar{'lonHostID'}; + + foreach my $line (split(/\n/,$contents)) { + if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/))) { + chomp($line); + my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon)=split(/:/,$line); + if ($id eq $me) { + open(PIPE, " /usr/bin/host $name |") || die "Cant' make host pipeline"; + my $hostinfo = ; + close PIPE; + + my ($hostname, $has, $address, $ipnew) = split(/ /,$hostinfo); + &logthis(''. + "hostname = $hostname me = $me, name = $name actual ip = $ipnew "); + + if ($hostname eq $name) { # Lookup succeeded.. + &logthis(' look up ok '); + $ip = $ipnew; + } else { + &logthis(' Lookup failed: ' + .$hostname." ne $name "); + } + # Reconstruct the host line and append to adjusted: + + my $newline = "$id:$domain:$role:$name:$ip"; + if($maxcon ne "") { # Not all hosts have loncnew tuning params + $newline .= ":$maxcon:$idleto:$mincon"; + } + $adjusted .= $newline."\n"; + + } else { # Not me, pass unmodified. + $adjusted .= $line."\n"; + } + } else { # Blank or comment never re-written. + $adjusted .= $line."\n"; # Pass blanks and comments as is. + } + } + return $adjusted; +} # # InstallFile: Called to install an administrative file: # - The file is created with .tmp @@ -354,6 +426,16 @@ sub PushFile { &logthis(' Pushfile: backed up ' .$tablefile." to $backupfile"); + # If the file being pushed is the host file, we adjust the entry for ourself so that the + # IP will be our current IP as looked up in dns. Note this is only 99% good as it's possible + # to conceive of conditions where we don't have a DNS entry locally. This is possible in a + # network sense but it doesn't make much sense in a LonCAPA sense so we ignore (for now) + # that possibilty. + + if($filename eq "host") { + $contents = AdjustHostContents($contents); + } + # Install the new file: if(!InstallFile($tablefile, $contents)) { @@ -583,8 +665,13 @@ sub ReadHostTable { } # # Reload the Apache daemon's state. +# This is done by invoking /home/httpd/perl/apachereload +# a setuid perl script that can be root for us to do this job. # sub ReloadApache { + my $execdir = $perlvar{'lonDaemons'}; + my $script = $execdir."/apachereload"; + system($script); } # @@ -613,7 +700,12 @@ sub UpdateHosts { foreach my $child (keys %children) { my $childip = $children{$child}; if(!$hostid{$childip}) { + logthis(' UpdateHosts killing child ' + ." $child for ip $childip "); kill('INT', $child); + } else { + logthis(' keeping child for ip ' + ." $childip (pid=$child) "); } } ReloadApache; @@ -651,7 +743,7 @@ sub checkchildren { } } $SIG{ALRM} = 'DEFAULT'; - $SIG{__DIE__} = \&cathcexception; + $SIG{__DIE__} = \&catchexception; } # --------------------------------------------------------------------- Logging @@ -1391,33 +1483,39 @@ sub make_new_child { } # -------------------------------------- fetch a user file from a remote server } elsif ($userinput =~ /^fetchuserfile/) { - my ($cmd,$fname)=split(/:/,$userinput); - my ($udom,$uname,$ufile)=split(/\//,$fname); - my $udir=propath($udom,$uname).'/userfiles'; - unless (-e $udir) { mkdir($udir,0770); } + my ($cmd,$fname)=split(/:/,$userinput); + my ($udom,$uname,$ufile)=split(/\//,$fname); + my $udir=propath($udom,$uname).'/userfiles'; + unless (-e $udir) { mkdir($udir,0770); } if (-e $udir) { - $ufile=~s/^[\.\~]+//; - $ufile=~s/\///g; - my $transname=$udir.'/'.$ufile; - my $remoteurl='http://'.$clientip.'/userfiles/'.$fname; - my $response; - { - my $ua=new LWP::UserAgent; - my $request=new HTTP::Request('GET',"$remoteurl"); - $response=$ua->request($request,$transname); - } - if ($response->is_error()) { - unlink($transname); - my $message=$response->status_line; - &logthis( - "LWP GET: $message for $fname ($remoteurl)"); - print $client "failed\n"; - } else { - print $client "ok\n"; - } - } else { - print $client "not_home\n"; - } + $ufile=~s/^[\.\~]+//; + $ufile=~s/\///g; + my $destname=$udir.'/'.$ufile; + my $transname=$udir.'/'.$ufile.'.in.transit'; + my $remoteurl='http://'.$clientip.'/userfiles/'.$fname; + my $response; + { + my $ua=new LWP::UserAgent; + my $request=new HTTP::Request('GET',"$remoteurl"); + $response=$ua->request($request,$transname); + } + if ($response->is_error()) { + unlink($transname); + my $message=$response->status_line; + &logthis("LWP GET: $message for $fname ($remoteurl)"); + print $client "failed\n"; + } else { + if (!rename($transname,$destname)) { + &logthis("Unable to move $transname to $destname"); + unlink($transname); + print $client "failed\n"; + } else { + print $client "ok\n"; + } + } + } else { + print $client "not_home\n"; + } # ------------------------------------------ authenticate access to a user file } elsif ($userinput =~ /^tokenauthuserfile/) { my ($cmd,$fname,$session)=split(/:/,$userinput);