--- loncom/lond 2009/10/21 16:14:24 1.431
+++ loncom/lond 2012/04/26 20:00:57 1.493
@@ -2,7 +2,7 @@
# The LearningOnline Network
# lond "LON Daemon" Server (port "LOND" 5663)
#
-# $Id: lond,v 1.431 2009/10/21 16:14:24 raeburn Exp $
+# $Id: lond,v 1.493 2012/04/26 20:00:57 droeschl Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -15,6 +15,7 @@
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
@@ -33,6 +34,7 @@ use strict;
use lib '/home/httpd/lib/perl/';
use LONCAPA;
use LONCAPA::Configuration;
+use LONCAPA::Lond;
use IO::Socket;
use IO::File;
@@ -42,7 +44,6 @@ use Crypt::IDEA;
use LWP::UserAgent();
use Digest::MD5 qw(md5_hex);
use GDBM_File;
-use Authen::Krb4;
use Authen::Krb5;
use localauth;
use localenroll;
@@ -53,13 +54,14 @@ use LONCAPA::lonlocal;
use LONCAPA::lonssl;
use Fcntl qw(:flock);
use Apache::lonnet;
+use Mail::Send;
my $DEBUG = 0; # Non zero to enable debug log entries.
my $status='';
my $lastlog='';
-my $VERSION='$Revision: 1.431 $'; #' stupid emacs
+my $VERSION='$Revision: 1.493 $'; #' stupid emacs
my $remoteVERSION;
my $currenthostid="default";
my $currentdomainid;
@@ -67,6 +69,9 @@ my $currentdomainid;
my $client;
my $clientip; # IP address of client.
my $clientname; # LonCAPA name of client.
+my $clientversion; # LonCAPA version running on client.
+my $clienthomedom; # LonCAPA domain of homeID for client.
+ # primary library server.
my $server;
@@ -88,6 +93,8 @@ my %managers; # Ip -> manager names
my %perlvar; # Will have the apache conf defined perl vars.
+my $dist;
+
#
# The hash below is used for command dispatching, and is therefore keyed on the request keyword.
# Each element of the hash contains a reference to an array that contains:
@@ -417,8 +424,11 @@ sub ReadManagerTable {
my $tablename = $perlvar{'lonTabDir'}."/managers.tab";
if (!open (MANAGERS, $tablename)) {
- logthis('No manager table. Nobody can manage!!');
- return;
+ my $hostname = &Apache::lonnet::hostname($perlvar{'lonHostID'});
+ if (&Apache::lonnet::is_LC_dns($hostname)) {
+ &logthis('No manager table. Nobody can manage!!');
+ }
+ return;
}
while(my $host = ) {
chomp($host);
@@ -443,7 +453,7 @@ sub ReadManagerTable {
}
} else {
logthis(' existing host'." $host\n");
- $managers{&Apache::lonnet::get_host_ip($host)} = $host; # Use info from cluster tab if clumemeber
+ $managers{&Apache::lonnet::get_host_ip($host)} = $host; # Use info from cluster tab if cluster memeber
}
}
}
@@ -505,7 +515,8 @@ sub AdjustHostContents {
my $me = $perlvar{'lonHostID'};
foreach my $line (split(/\n/,$contents)) {
- if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/))) {
+ if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/) ||
+ ($line =~ /^\s*\^/))) {
chomp($line);
my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon)=split(/:/,$line);
if ($id eq $me) {
@@ -593,11 +604,8 @@ sub InstallFile {
#
# ConfigFileFromSelector: converts a configuration file selector
# into a configuration file pathname.
-# It's probably no longer necessary to preserve
-# special handling of hosts or domain as those
-# files have been superceded by dns_hosts, dns_domain.
-# The default action is just to prepend the directory
-# and append .tab
+# Supports the following file selectors:
+# hosts, domain, dns_hosts, dns_domain
#
#
# Parameters:
@@ -610,15 +618,11 @@ sub ConfigFileFromSelector {
my $tablefile;
my $tabledir = $perlvar{'lonTabDir'}.'/';
- if ($selector eq "hosts") {
- $tablefile = $tabledir."hosts.tab";
- } elsif ($selector eq "domain") {
- $tablefile = $tabledir."domain.tab";
- } else {
+ if (($selector eq "hosts") || ($selector eq "domain") ||
+ ($selector eq "dns_hosts") || ($selector eq "dns_domain")) {
$tablefile = $tabledir.$selector.'.tab';
}
return $tablefile;
-
}
#
# PushFile: Called to do an administrative push of a file.
@@ -644,6 +648,8 @@ sub PushFile {
# supported:
# hosts.tab ($filename eq host).
# domain.tab ($filename eq domain).
+ # dns_hosts.tab ($filename eq dns_host).
+ # dns_domain.tab ($filename eq dns_domain).
# Construct the destination filename or reject the request.
#
# lonManage is supposed to ensure this, however this session could be
@@ -675,11 +681,31 @@ sub PushFile {
return "error:$!";
} else {
&logthis(' Installed new '.$tablefile
- ."");
-
+ ." - transaction by: $clientname ($clientip)");
+ my $adminmail = $perlvar{'lonAdmEMail'};
+ my $admindom = &Apache::lonnet::host_domain($perlvar{'lonHostID'});
+ if ($admindom ne '') {
+ my %domconfig =
+ &Apache::lonnet::get_dom('configuration',['contacts'],$admindom);
+ if (ref($domconfig{'contacts'}) eq 'HASH') {
+ if ($domconfig{'contacts'}{'adminemail'} ne '') {
+ $adminmail = $domconfig{'contacts'}{'adminemail'};
+ }
+ }
+ }
+ if ($adminmail =~ /^[^\@]+\@[^\@]+$/) {
+ my $msg = new Mail::Send;
+ $msg->to($adminmail);
+ $msg->subject('LON-CAPA DNS update on '.$perlvar{'lonHostID'});
+ $msg->add('Content-type','text/plain; charset=UTF-8');
+ if (my $fh = $msg->open()) {
+ print $fh 'Update to '.$tablefile.' from Cluster Manager '.
+ "$clientname ($clientip)\n";
+ $fh->close;
+ }
+ }
}
-
# Indicate success:
return "ok";
@@ -975,6 +1001,9 @@ sub read_profile {
&GDBM_READER());
if ($hashref) {
my @queries=split(/\&/,$what);
+ if ($namespace eq 'roles') {
+ @queries = map { &unescape($_); } @queries;
+ }
my $qresult='';
for (my $i=0;$i<=$#queries;$i++) {
@@ -1068,7 +1097,7 @@ sub pong_handler {
# Implicit Inputs:
# $currenthostid - Global variable that carries the name of the host
# known as.
-# $clientname - Global variable that carries the name of the hsot we're connected to.
+# $clientname - Global variable that carries the name of the host we're connected to.
# Returns:
# 1 - Ok to continue processing.
# 0 - Program should exit.
@@ -1107,7 +1136,7 @@ sub establish_key_handler {
# Implicit Inputs:
# $currenthostid - Global variable that carries the name of the host
# known as.
-# $clientname - Global variable that carries the name of the hsot we're connected to.
+# $clientname - Global variable that carries the name of the host we're connected to.
# Returns:
# 1 - Ok to continue processing.
# 0 - Program should exit.
@@ -1116,6 +1145,8 @@ sub establish_key_handler {
sub load_handler {
my ($cmd, $tail, $replyfd) = @_;
+
+
# Get the load average from /proc/loadavg and calculate it as a percentage of
# the allowed load limit as set by the perl global variable lonLoadLim
@@ -1144,7 +1175,7 @@ sub load_handler {
# Implicit Inputs:
# $currenthostid - Global variable that carries the name of the host
# known as.
-# $clientname - Global variable that carries the name of the hsot we're connected to.
+# $clientname - Global variable that carries the name of the host we're connected to.
# Returns:
# 1 - Ok to continue processing.
# 0 - Program should exit
@@ -1613,6 +1644,74 @@ sub ls3_handler {
}
®ister_handler("ls3", \&ls3_handler, 0, 1, 0);
+sub read_lonnet_global {
+ my ($cmd,$tail,$client) = @_;
+ my $userinput = "$cmd:$tail";
+ my $requested = &Apache::lonnet::thaw_unescape($tail);
+ my $result;
+ my %packagevars = (
+ spareid => \%Apache::lonnet::spareid,
+ perlvar => \%Apache::lonnet::perlvar,
+ );
+ my %limit_to = (
+ perlvar => {
+ lonOtherAuthen => 1,
+ lonBalancer => 1,
+ lonVersion => 1,
+ lonSysEMail => 1,
+ lonHostID => 1,
+ lonRole => 1,
+ lonDefDomain => 1,
+ lonLoadLim => 1,
+ lonUserLoadLim => 1,
+ }
+ );
+ if (ref($requested) eq 'HASH') {
+ foreach my $what (keys(%{$requested})) {
+ my $response;
+ my $items = {};
+ if (exists($packagevars{$what})) {
+ if (ref($limit_to{$what}) eq 'HASH') {
+ foreach my $varname (keys(%{$packagevars{$what}})) {
+ if ($limit_to{$what}{$varname}) {
+ $items->{$varname} = $packagevars{$what}{$varname};
+ }
+ }
+ } else {
+ $items = $packagevars{$what};
+ }
+ if ($what eq 'perlvar') {
+ if (!exists($packagevars{$what}{'lonBalancer'})) {
+ if ($dist =~ /^(centos|rhes|fedora|scientific)/) {
+ my $othervarref=LONCAPA::Configuration::read_conf('httpd.conf');
+ if (ref($othervarref) eq 'HASH') {
+ $items->{'lonBalancer'} = $othervarref->{'lonBalancer'};
+ }
+ }
+ }
+ }
+ $response = &Apache::lonnet::freeze_escape($items);
+ }
+ $result .= &escape($what).'='.$response.'&';
+ }
+ }
+ $result =~ s/\&$//;
+ &Reply($client,\$result,$userinput);
+ return 1;
+}
+®ister_handler("readlonnetglobal", \&read_lonnet_global, 0, 1, 0);
+
+sub server_devalidatecache_handler {
+ my ($cmd,$tail,$client) = @_;
+ my $userinput = "$cmd:$tail";
+ my ($name,$id) = map { &unescape($_); } split(/:/,$tail);
+ &Apache::lonnet::devalidate_cache_new($name,$id);
+ my $result = 'ok';
+ &Reply($client,\$result,$userinput);
+ return 1;
+}
+®ister_handler("devalidatecache", \&server_devalidatecache_handler, 0, 1, 0);
+
sub server_timezone_handler {
my ($cmd,$tail,$client) = @_;
my $userinput = "$cmd:$tail";
@@ -1653,6 +1752,23 @@ sub server_loncaparev_handler {
}
®ister_handler("serverloncaparev", \&server_loncaparev_handler, 0, 1, 0);
+sub server_homeID_handler {
+ my ($cmd,$tail,$client) = @_;
+ my $userinput = "$cmd:$tail";
+ &Reply($client,\$perlvar{'lonHostID'},$userinput);
+ return 1;
+}
+®ister_handler("serverhomeID", \&server_homeID_handler, 0, 1, 0);
+
+sub server_distarch_handler {
+ my ($cmd,$tail,$client) = @_;
+ my $userinput = "$cmd:$tail";
+ my $reply = &distro_and_arch();
+ &Reply($client,\$reply,$userinput);
+ return 1;
+}
+®ister_handler("serverdistarch", \&server_distarch_handler, 0, 1, 0);
+
# Process a reinit request. Reinit requests that either
# lonc or lond be reinitialized so that an updated
# host.tab or domain.tab can be processed.
@@ -1762,15 +1878,45 @@ sub authenticate_handler {
# upass - User's password.
# checkdefauth - Pass to validate_user() to try authentication
# with default auth type(s) if no user account.
+ # clientcancheckhost - Passed by clients with functionality in lonauth.pm
+ # to check if session can be hosted.
- my ($udom, $uname, $upass, $checkdefauth)=split(/:/,$tail);
+ my ($udom, $uname, $upass, $checkdefauth, $clientcancheckhost)=split(/:/,$tail);
&Debug(" Authenticate domain = $udom, user = $uname, password = $upass, checkdefauth = $checkdefauth");
chomp($upass);
$upass=&unescape($upass);
my $pwdcorrect = &validate_user($udom,$uname,$upass,$checkdefauth);
if($pwdcorrect) {
- &Reply( $client, "authorized\n", $userinput);
+ my $canhost = 1;
+ unless ($clientcancheckhost) {
+ my $uprimary_id = &Apache::lonnet::domain($udom,'primary');
+ my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id);
+ my @intdoms;
+ my $internet_names = &Apache::lonnet::get_internet_names($clientname);
+ if (ref($internet_names) eq 'ARRAY') {
+ @intdoms = @{$internet_names};
+ }
+ unless ($uint_dom ne '' && grep(/^\Q$uint_dom\E$/,@intdoms)) {
+ my ($remote,$hosted);
+ my $remotesession = &get_usersession_config($udom,'remotesession');
+ if (ref($remotesession) eq 'HASH') {
+ $remote = $remotesession->{'remote'}
+ }
+ my $hostedsession = &get_usersession_config($clienthomedom,'hostedsession');
+ if (ref($hostedsession) eq 'HASH') {
+ $hosted = $hostedsession->{'hosted'};
+ }
+ $canhost = &Apache::lonnet::can_host_session($udom,$clientname,
+ $clientversion,
+ $remote,$hosted);
+ }
+ }
+ if ($canhost) {
+ &Reply( $client, "authorized\n", $userinput);
+ } else {
+ &Reply( $client, "not_allowed_to_host\n", $userinput);
+ }
#
# Bad credentials: Failed to authorize
#
@@ -1924,7 +2070,7 @@ sub add_user_handler {
."makeuser";
}
unless ($fperror) {
- my $result=&make_passwd_file($uname, $umode,$npass, $passfilename);
+ my $result=&make_passwd_file($uname,$udom,$umode,$npass, $passfilename);
&Reply($client,\$result, $userinput); #BUGBUG - could be fail
} else {
&Failure($client, \$fperror, $userinput);
@@ -1999,7 +2145,7 @@ sub change_authentication_handler {
&Failure($client, \$result);
}
} else {
- my $result=&make_passwd_file($uname, $umode,$npass,$passfilename);
+ my $result=&make_passwd_file($uname,$udom,$umode,$npass,$passfilename);
#
# If the current auth mode is internal, and the old auth mode was
# unix, or krb*, and the user is an author for this domain,
@@ -2061,16 +2207,10 @@ sub is_home_handler {
®ister_handler("home", \&is_home_handler, 0,1,0);
#
-# Process an update request for a resource?? I think what's going on here is
-# that a resource has been modified that we hold a subscription to.
+# Process an update request for a resource.
+# A resource has been modified that we hold a subscription to.
# If the resource is not local, then we must update, or at least invalidate our
# cached copy of the resource.
-# FUTURE WORK:
-# I need to look at this logic carefully. My druthers would be to follow
-# typical caching logic, and simple invalidate the cache, drop any subscription
-# an let the next fetch start the ball rolling again... however that may
-# actually be more difficult than it looks given the complex web of
-# proxy servers.
# Parameters:
# $cmd - The command that got us here.
# $tail - Tail of the command (remaining parameters).
@@ -2094,20 +2234,30 @@ sub update_resource_handler {
my $ownership=ishome($fname);
if ($ownership eq 'not_owner') {
if (-e $fname) {
+ # Delete preview file, if exists
+ unlink("$fname.tmp");
+ # Get usage stats
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks)=stat($fname);
my $now=time;
my $since=$now-$atime;
+ # If the file has not been used within lonExpire seconds,
+ # unsubscribe from it and delete local copy
if ($since>$perlvar{'lonExpire'}) {
my $reply=&Apache::lonnet::reply("unsub:$fname","$clientname");
&devalidate_meta_cache($fname);
unlink("$fname");
unlink("$fname.meta");
} else {
+ # Yes, this is in active use. Get a fresh copy. Since it might be in
+ # very active use and huge (like a movie), copy it to "in.transfer" filename first.
my $transname="$fname.in.transfer";
my $remoteurl=&Apache::lonnet::reply("sub:$fname","$clientname");
my $response;
- alarm(120);
+# FIXME: cannot replicate files that take more than two minutes to transfer?
+# alarm(120);
+# FIXME: this should use the LWP mechanism, not internal alarms.
+ alarm(1200);
{
my $ua=new LWP::UserAgent;
my $request=new HTTP::Request('GET',"$remoteurl");
@@ -2115,11 +2265,13 @@ sub update_resource_handler {
}
alarm(0);
if ($response->is_error()) {
+# FIXME: we should probably clean up here instead of just whine
unlink($transname);
my $message=$response->status_line;
&logthis("LWP GET: $message for $fname ($remoteurl)");
} else {
if ($remoteurl!~/\.meta$/) {
+# FIXME: isn't there an internal LWP mechanism for this?
alarm(120);
{
my $ua=new LWP::UserAgent;
@@ -2131,6 +2283,7 @@ sub update_resource_handler {
}
alarm(0);
}
+ # we successfully transfered, copy file over to real name
rename($transname,$fname);
&devalidate_meta_cache($fname);
}
@@ -2192,7 +2345,10 @@ sub fetch_user_file_handler {
my $destname=$udir.'/'.$ufile;
my $transname=$udir.'/'.$ufile.'.in.transit';
- my $remoteurl='http://'.$clientip.'/userfiles/'.$fname;
+ my $clientprotocol=$Apache::lonnet::protocol{$clientname};
+ $clientprotocol = 'http' if ($clientprotocol ne 'https');
+ my $clienthost = &Apache::lonnet::hostname($clientname);
+ my $remoteurl=$clientprotocol.'://'.$clienthost.'/userfiles/'.$fname;
my $response;
Debug("Remote URL : $remoteurl Transfername $transname Destname: $destname");
alarm(120);
@@ -2368,7 +2524,6 @@ sub user_has_session_handler {
my ($udom, $uname) = map { &unescape($_) } (split(/:/, $tail));
- &logthis("Looking for $udom $uname");
opendir(DIR,$perlvar{'lonIDsDir'});
my $filename;
while ($filename=readdir(DIR)) {
@@ -3087,6 +3242,9 @@ sub dump_profile_database {
# that is matched against
# database keywords to do
# selective dumps.
+# range - optional range of entries
+# e.g., 10-20 would return the
+# 10th to 19th items, etc.
# $client - Channel open on the client.
# Returns:
# 1 - Continue processing.
@@ -3096,56 +3254,12 @@ sub dump_profile_database {
sub dump_with_regexp {
my ($cmd, $tail, $client) = @_;
-
- my $userinput = "$cmd:$tail";
-
- my ($udom,$uname,$namespace,$regexp,$range)=split(/:/,$tail);
- if (defined($regexp)) {
- $regexp=&unescape($regexp);
- } else {
- $regexp='.';
- }
- my ($start,$end);
- if (defined($range)) {
- if ($range =~/^(\d+)\-(\d+)$/) {
- ($start,$end) = ($1,$2);
- } elsif ($range =~/^(\d+)$/) {
- ($start,$end) = (0,$1);
- } else {
- undef($range);
- }
- }
- my $hashref = &tie_user_hash($udom, $uname, $namespace,
- &GDBM_READER());
- if ($hashref) {
- my $qresult='';
- my $count=0;
- while (my ($key,$value) = each(%$hashref)) {
- if ($regexp eq '.') {
- $count++;
- if (defined($range) && $count >= $end) { last; }
- if (defined($range) && $count < $start) { next; }
- $qresult.=$key.'='.$value.'&';
- } else {
- my $unescapeKey = &unescape($key);
- if (eval('$unescapeKey=~/$regexp/')) {
- $count++;
- if (defined($range) && $count >= $end) { last; }
- if (defined($range) && $count < $start) { next; }
- $qresult.="$key=$value&";
- }
- }
- }
- if (&untie_user_hash($hashref)) {
- chop($qresult);
- &Reply($client, \$qresult, $userinput);
- } else {
- &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ".
- "while attempting dump\n", $userinput);
- }
+ my $res = LONCAPA::Lond::dump_with_regexp($tail, $clientname, $clientversion);
+
+ if ($res =~ /^error:/) {
+ Failure($client, \$res, "$cmd:$tail");
} else {
- &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
- "while attempting dump\n", $userinput);
+ Reply($client, \$res, "$cmd:$tail");
}
return 1;
@@ -3714,6 +3828,9 @@ sub put_course_id_hash_handler {
# createdafter - include courses for which creation date followed this date.
# creationcontext - include courses created in specified context
#
+# domcloner - flag to indicate if user can create CCs in course's domain.
+# If so, ability to clone course is automatic.
+#
# $client - The socket open on the client.
# Returns:
# 1 - Continue processing.
@@ -3726,7 +3843,7 @@ sub dump_course_id_handler {
my ($udom,$since,$description,$instcodefilter,$ownerfilter,$coursefilter,
$typefilter,$regexp_ok,$rtn_as_hash,$selfenrollonly,$catfilter,$showhidden,
$caller,$cloner,$cc_clone_list,$cloneonly,$createdbefore,$createdafter,
- $creationcontext) =split(/:/,$tail);
+ $creationcontext,$domcloner) =split(/:/,$tail);
my $now = time;
my ($cloneruname,$clonerudom,%cc_clone);
if (defined($description)) {
@@ -3799,9 +3916,8 @@ sub dump_course_id_handler {
} else {
$creationcontext = '.';
}
-
my $unpack = 1;
- if ($description eq '.' && $instcodefilter eq '.' && $coursefilter eq '.' &&
+ if ($description eq '.' && $instcodefilter eq '.' && $ownerfilter eq '.' &&
$typefilter eq '.') {
$unpack = 0;
}
@@ -3830,7 +3946,9 @@ sub dump_course_id_handler {
next if ($since > 1);
}
$is_hash = 1;
- if (defined($clonerudom)) {
+ if ($domcloner) {
+ $canclone = 1;
+ } elsif (defined($clonerudom)) {
if ($items->{'cloners'}) {
my @cloneable = split(',',$items->{'cloners'});
if (@cloneable) {
@@ -3858,6 +3976,19 @@ sub dump_course_id_handler {
$items->{'cloners'} = $cloneruname.':'.$clonerudom;
$valchange = 1;
}
+ unless ($canclone) {
+ if ($items->{'owner'} =~ /:/) {
+ if ($items->{'owner'} eq $cloner) {
+ $canclone = 1;
+ }
+ } elsif ($cloner eq $items->{'owner'}.':'.$udom) {
+ $canclone = 1;
+ }
+ if ($canclone) {
+ $items->{'cloners'} = $cloneruname.':'.$clonerudom;
+ $valchange = 1;
+ }
+ }
}
}
if ($unpack || !$rtn_as_hash) {
@@ -4058,6 +4189,53 @@ sub dump_course_id_handler {
}
®ister_handler("courseiddump", \&dump_course_id_handler, 0, 1, 0);
+sub course_lastaccess_handler {
+ my ($cmd, $tail, $client) = @_;
+ my $userinput = "$cmd:$tail";
+ my ($cdom,$cnum) = split(':',$tail);
+ my (%lastaccess,$qresult);
+ my $hashref = &tie_domain_hash($cdom, "nohist_courseids", &GDBM_WRCREAT());
+ if ($hashref) {
+ while (my ($key,$value) = each(%$hashref)) {
+ my ($unesc_key,$lasttime);
+ $unesc_key = &unescape($key);
+ if ($cnum) {
+ next unless ($unesc_key =~ /\Q$cdom\E_\Q$cnum\E$/);
+ }
+ if ($unesc_key =~ /^lasttime:($LONCAPA::match_domain\_$LONCAPA::match_courseid)/) {
+ $lastaccess{$1} = $value;
+ } else {
+ my $items = &Apache::lonnet::thaw_unescape($value);
+ if (ref($items) eq 'HASH') {
+ unless ($lastaccess{$unesc_key}) {
+ $lastaccess{$unesc_key} = '';
+ }
+ } else {
+ my @courseitems = split(':',$value);
+ $lastaccess{$unesc_key} = pop(@courseitems);
+ }
+ }
+ }
+ foreach my $cid (sort(keys(%lastaccess))) {
+ $qresult.=&escape($cid).'='.$lastaccess{$cid}.'&';
+ }
+ if (&untie_domain_hash($hashref)) {
+ if ($qresult) {
+ chop($qresult);
+ }
+ &Reply($client, \$qresult, $userinput);
+ } else {
+ &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
+ "while attempting lastacourseaccess\n", $userinput);
+ }
+ } else {
+ &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
+ "while attempting lastcourseaccess\n", $userinput);
+ }
+ return 1;
+}
+®ister_handler("courselastaccess",\&course_lastaccess_handler, 0, 1, 0);
+
#
# Puts an unencrypted entry in a namespace db file at the domain level
#
@@ -4123,6 +4301,7 @@ sub put_domain_handler {
sub get_domain_handler {
my ($cmd, $tail, $client) = @_;
+
my $userinput = "$client:$tail";
my ($udom,$namespace,$what)=split(/:/,$tail,3);
@@ -4267,7 +4446,8 @@ sub get_id_handler {
sub put_dcmail_handler {
my ($cmd,$tail,$client) = @_;
my $userinput = "$cmd:$tail";
-
+
+
my ($udom,$what)=split(/:/,$tail);
chomp($what);
my $hashref = &tie_domain_hash($udom, "nohist_dcmail", &GDBM_WRCREAT());
@@ -4531,7 +4711,7 @@ sub tmp_put_handler {
}
my ($id,$store);
$tmpsnum++;
- if ($context eq 'resetpw') {
+ if (($context eq 'resetpw') || ($context eq 'createaccount')) {
$id = &md5_hex(&md5_hex(time.{}.rand().$$));
} else {
$id = $$.'_'.$clientip.'_'.$tmpsnum;
@@ -4849,10 +5029,11 @@ sub get_sections_handler {
sub validate_course_owner_handler {
my ($cmd, $tail, $client) = @_;
my $userinput = "$cmd:$tail";
- my ($inst_course_id, $owner, $cdom) = split(/:/, $tail);
-
+ my ($inst_course_id, $owner, $cdom, $coowners) = split(/:/, $tail);
+
$owner = &unescape($owner);
- my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom);
+ $coowners = &unescape($coowners);
+ my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom,$coowners);
&Reply($client, \$outcome, $userinput);
@@ -5840,7 +6021,7 @@ if (-e $pidfile) {
$server = IO::Socket::INET->new(LocalPort => $perlvar{'londPort'},
Type => SOCK_STREAM,
Proto => 'tcp',
- Reuse => 1,
+ ReuseAddr => 1,
Listen => 10 )
or die "making socket: $@\n";
@@ -5903,9 +6084,13 @@ sub HUPSMAN { # sig
# 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);
+# --------------------------- Handle case of another apachereload process (locking)
+ if (&LONCAPA::try_to_lock('/tmp/lock_apachereload')) {
+ my $execdir = $perlvar{'lonDaemons'};
+ my $script = $execdir."/apachereload";
+ system($script);
+ unlink('/tmp/lock_apachereload'); # Remove the lock file.
+ }
}
#
@@ -6016,6 +6201,9 @@ sub Debug {
# reply - Text to send to client.
# request - Original request from client.
#
+#NOTE $reply must be terminated by exactly *one* \n. If $reply is a reference
+#this is done automatically ($$reply must not contain any \n in this case).
+#If $reply is a string the caller has to ensure this.
sub Reply {
my ($fd, $reply, $request) = @_;
if (ref($reply)) {
@@ -6078,7 +6266,7 @@ sub logstatus {
sub initnewstatus {
my $docdir=$perlvar{'lonDocRoot'};
my $fh=IO::File->new(">$docdir/lon-status/londstatus.txt");
- my $now=time;
+ my $now=time();
my $local=localtime($now);
print $fh "LOND status $local - parent $$\n\n";
opendir(DIR,"$docdir/lon-status/londchld");
@@ -6167,8 +6355,16 @@ $SIG{USR2} = \&UpdateHosts;
# Read the host hashes:
&Apache::lonnet::load_hosts_tab();
+my %iphost = &Apache::lonnet::get_iphost(1);
+
+$dist=`$perlvar{'lonDaemons'}/distprobe`;
-my $dist=`$perlvar{'lonDaemons'}/distprobe`;
+my $arch = `uname -i`;
+chomp($arch);
+if ($arch eq 'unknown') {
+ $arch = `uname -m`;
+ chomp($arch);
+}
# --------------------------------------------------------------
# Accept connections. When a connection comes in, it is validated
@@ -6227,6 +6423,7 @@ sub make_new_child {
or die "Can't unblock SIGINT for fork: $!\n";
$children{$pid} = $clientip;
&status('Started child '.$pid);
+ close($client);
return;
} else {
# Child can *not* return from this subroutine.
@@ -6235,6 +6432,13 @@ sub make_new_child {
#don't get intercepted
$SIG{USR1}= \&logstatus;
$SIG{ALRM}= \&timeout;
+ #
+ # Block sigpipe as it gets thrownon socket disconnect and we want to
+ # deal with that as a read faiure instead.
+ #
+ my $blockset = POSIX::SigSet->new(SIGPIPE);
+ sigprocmask(SIG_BLOCK, $blockset);
+
$lastlog='Forked ';
$status='Forked';
@@ -6263,7 +6467,7 @@ sub make_new_child {
&ReadManagerTable();
my $clientrec=defined(&Apache::lonnet::get_hosts_from_ip($outsideip));
my $ismanager=($managers{$outsideip} ne undef);
- $clientname = "[unknonwn]";
+ $clientname = "[unknown]";
if($clientrec) { # Establish client type.
$ConnectionType = "client";
$clientname = (&Apache::lonnet::get_hosts_from_ip($outsideip))[-1];
@@ -6291,7 +6495,11 @@ sub make_new_child {
#
# If the remote is attempting a local init... give that a try:
#
- my ($i, $inittype) = split(/:/, $remotereq);
+ (my $i, my $inittype, $clientversion) = split(/:/, $remotereq);
+ # For LON-CAPA 2.9, the client session will have sent its LON-CAPA
+ # version when initiating the connection. For LON-CAPA 2.8 and older,
+ # the version is retrieved from the global %loncaparevs in lonnet.pm.
+ $clientversion ||= $Apache::lonnet::loncaparevs{$clientname};
# If the connection type is ssl, but I didn't get my
# certificate files yet, then I'll drop back to
@@ -6311,6 +6519,7 @@ sub make_new_child {
}
if($inittype eq "local") {
+ $clientversion = $perlvar{'lonVersion'};
my $key = LocalConnection($client, $remotereq);
if($key) {
Debug("Got local key $key");
@@ -6318,7 +6527,7 @@ sub make_new_child {
my $cipherkey = pack("H32", $key);
$cipher = new IDEA($cipherkey);
print $client "ok:local\n";
- &logthis(''
. "Successful local authentication ");
$keymode = "local"
} else {
@@ -6382,6 +6591,9 @@ sub make_new_child {
# ------------------------------------------------------------ Process requests
my $keep_going = 1;
my $user_input;
+ my $clienthost = &Apache::lonnet::hostname($clientname);
+ my $clientserverhomeID = &Apache::lonnet::get_server_homeID($clienthost);
+ $clienthomedom = &Apache::lonnet::host_domain($clientserverhomeID);
while(($user_input = get_request) && $keep_going) {
alarm(120);
Debug("Main: Got $user_input\n");
@@ -6431,22 +6643,29 @@ sub is_author {
# Author role should show up as a key /domain/_au
- my $key = "/$domain/_au";
my $value;
- if (defined($hashref)) {
- $value = $hashref->{$key};
- }
+ if ($hashref) {
- if(defined($value)) {
- &Debug("$user @ $domain is an author");
+ my $key = "/$domain/_au";
+ if (defined($hashref)) {
+ $value = $hashref->{$key};
+ if(!untie_user_hash($hashref)) {
+ return 'error: ' . ($!+0)." untie (GDBM) Failed";
+ }
+ }
+
+ if(defined($value)) {
+ &Debug("$user @ $domain is an author");
+ }
+ } else {
+ return 'error: '.($!+0)." tie (GDBM) Failed";
}
return defined($value);
}
#
# Checks to see if the input roleput request was to set
-# an author role. If so, invokes the lchtmldir script to set
-# up a correct public_html
+# an author role. If so, creates construction space
# Parameters:
# request - The request sent to the rolesput subchunk.
# We're looking for /domain/_au
@@ -6456,16 +6675,15 @@ sub is_author {
#
sub manage_permissions {
my ($request, $domain, $user, $authtype) = @_;
-
- &Debug("manage_permissions: $request $domain $user $authtype");
-
# See if the request is of the form /$domain/_au
if($request =~ /^(\/\Q$domain\E\/_au)$/) { # It's an author rolesput...
- my $execdir = $perlvar{'lonDaemons'};
- my $userhome= "/home/$user" ;
- &logthis("system $execdir/lchtmldir $userhome $user $authtype");
- &Debug("Setting homedir permissions for $userhome");
- system("$execdir/lchtmldir $userhome $user $authtype");
+ my $path=$perlvar{'lonDocRoot'}."/priv/$domain";
+ unless (-e $path) {
+ mkdir($path);
+ }
+ unless (-e $path.'/'.$user) {
+ mkdir($path.'/'.$user);
+ }
}
}
@@ -6540,9 +6758,7 @@ sub rewrite_password_file {
# Returns the authorization type or nouser if there is no such user.
#
-sub get_auth_type
-{
-
+sub get_auth_type {
my ($domain, $user) = @_;
Debug("get_auth_type( $domain, $user ) \n");
@@ -6637,54 +6853,24 @@ sub validate_user {
} else {
$validated = 0;
}
- }
- elsif ($howpwd eq "krb4") { # user is in kerberos 4 auth. domain.
- if(! ($password =~ /$null/) ) {
- my $k4error = &Authen::Krb4::get_pw_in_tkt($user,
- "",
- $contentpwd,,
- 'krbtgt',
- $contentpwd,
- 1,
- $password);
- if(!$k4error) {
- $validated = 1;
- } else {
- $validated = 0;
- &logthis('krb4: '.$user.', '.$contentpwd.', '.
- &Authen::Krb4::get_err_txt($Authen::Krb4::error));
- }
- } else {
- $validated = 0; # Password has a match with null.
- }
+ } elsif ($howpwd eq "krb4") { # user is in kerberos 4 auth. domain.
+ my $checkwithkrb5 = 0;
+ if ($dist =~/^fedora(\d+)$/) {
+ if ($1 > 11) {
+ $checkwithkrb5 = 1;
+ }
+ } elsif ($dist =~ /^suse([\d.]+)$/) {
+ if ($1 > 11.1) {
+ $checkwithkrb5 = 1;
+ }
+ }
+ if ($checkwithkrb5) {
+ $validated = &krb5_authen($password,$null,$user,$contentpwd);
+ } else {
+ $validated = &krb4_authen($password,$null,$user,$contentpwd);
+ }
} elsif ($howpwd eq "krb5") { # User is in kerberos 5 auth. domain.
- if(!($password =~ /$null/)) { # Null password not allowed.
- my $krbclient = &Authen::Krb5::parse_name($user.'@'
- .$contentpwd);
- my $krbservice = "krbtgt/".$contentpwd."\@".$contentpwd;
- my $krbserver = &Authen::Krb5::parse_name($krbservice);
- my $credentials= &Authen::Krb5::cc_default();
- $credentials->initialize(&Authen::Krb5::parse_name($user.'@'
- .$contentpwd));
- my $krbreturn;
- if (exists(&Authen::Krb5::get_init_creds_password)) {
- $krbreturn =
- &Authen::Krb5::get_init_creds_password($krbclient,$password,
- $krbservice);
- $validated = (ref($krbreturn) eq 'Authen::Krb5::Creds');
- } else {
- $krbreturn =
- &Authen::Krb5::get_in_tkt_with_password($krbclient,$krbserver,
- $password,$credentials);
- $validated = ($krbreturn == 1);
- }
- if (!$validated) {
- &logthis('krb5: '.$user.', '.$contentpwd.', '.
- &Authen::Krb5::error());
- }
- } else {
- $validated = 0;
- }
+ $validated = &krb5_authen($password,$null,$user,$contentpwd);
} elsif ($howpwd eq "localauth") {
# Authenticate via installation specific authentcation method:
$validated = &localauth::localauth($user,
@@ -6715,6 +6901,65 @@ sub validate_user {
return $validated;
}
+sub krb4_authen {
+ my ($password,$null,$user,$contentpwd) = @_;
+ my $validated = 0;
+ if (!($password =~ /$null/) ) { # Null password not allowed.
+ eval {
+ require Authen::Krb4;
+ };
+ if (!$@) {
+ my $k4error = &Authen::Krb4::get_pw_in_tkt($user,
+ "",
+ $contentpwd,,
+ 'krbtgt',
+ $contentpwd,
+ 1,
+ $password);
+ if(!$k4error) {
+ $validated = 1;
+ } else {
+ $validated = 0;
+ &logthis('krb4: '.$user.', '.$contentpwd.', '.
+ &Authen::Krb4::get_err_txt($Authen::Krb4::error));
+ }
+ } else {
+ $validated = krb5_authen($password,$null,$user,$contentpwd);
+ }
+ }
+ return $validated;
+}
+
+sub krb5_authen {
+ my ($password,$null,$user,$contentpwd) = @_;
+ my $validated = 0;
+ if(!($password =~ /$null/)) { # Null password not allowed.
+ my $krbclient = &Authen::Krb5::parse_name($user.'@'
+ .$contentpwd);
+ my $krbservice = "krbtgt/".$contentpwd."\@".$contentpwd;
+ my $krbserver = &Authen::Krb5::parse_name($krbservice);
+ my $credentials= &Authen::Krb5::cc_default();
+ $credentials->initialize(&Authen::Krb5::parse_name($user.'@'
+ .$contentpwd));
+ my $krbreturn;
+ if (exists(&Authen::Krb5::get_init_creds_password)) {
+ $krbreturn =
+ &Authen::Krb5::get_init_creds_password($krbclient,$password,
+ $krbservice);
+ $validated = (ref($krbreturn) eq 'Authen::Krb5::Creds');
+ } else {
+ $krbreturn =
+ &Authen::Krb5::get_in_tkt_with_password($krbclient,$krbserver,
+ $password,$credentials);
+ $validated = ($krbreturn == 1);
+ }
+ if (!$validated) {
+ &logthis('krb5: '.$user.', '.$contentpwd.', '.
+ &Authen::Krb5::error());
+ }
+ }
+ return $validated;
+}
sub addline {
my ($fname,$hostid,$ip,$newline)=@_;
@@ -6927,7 +7172,9 @@ sub subscribe {
# the metadata
unless ($fname=~/\.meta$/) { &unsub("$fname.meta",$clientip); }
$fname=~s/\/home\/httpd\/html\/res/raw/;
- $fname="http://".&Apache::lonnet::hostname($perlvar{'lonHostID'})."/".$fname;
+ my $protocol = $Apache::lonnet::protocol{$perlvar{'lonHostID'}};
+ $protocol = 'http' if ($protocol ne 'https');
+ $fname=$protocol.'://'.&Apache::lonnet::hostname($perlvar{'lonHostID'})."/".$fname;
$result="$fname\n";
}
} else {
@@ -6969,7 +7216,7 @@ sub change_unix_password {
sub make_passwd_file {
- my ($uname, $umode,$npass,$passfilename)=@_;
+ my ($uname,$udom,$umode,$npass,$passfilename)=@_;
my $result="ok";
if ($umode eq 'krb4' or $umode eq 'krb5') {
{
@@ -7010,7 +7257,7 @@ sub make_passwd_file {
#
my $uid = getpwnam($uname);
if((defined $uid) && ($uid == 0)) {
- &logthis(">>>Attempted to create privilged account blocked");
+ &logthis(">>>Attempt to create privileged account blocked");
return "no_priv_account_error\n";
}
@@ -7022,6 +7269,7 @@ sub make_passwd_file {
&Debug("user = ".$uname.", Password =". $npass);
my $se = IO::File->new("|$execpath > $perlvar{'lonDaemons'}/logs/lcuseradd.log");
print $se "$uname\n";
+ print $se "$udom\n";
print $se "$npass\n";
print $se "$npass\n";
print $se "$lc_error_file\n"; # Status -> unique file.
@@ -7085,7 +7333,7 @@ sub sethost {
eq &Apache::lonnet::get_host_ip($hostid)) {
$currenthostid =$hostid;
$currentdomainid=&Apache::lonnet::host_domain($hostid);
- &logthis("Setting hostid to $hostid, and domain to $currentdomainid");
+# &logthis("Setting hostid to $hostid, and domain to $currentdomainid");
} else {
&logthis("Requested host id $hostid not an alias of ".
$perlvar{'lonHostID'}." refusing connection");
@@ -7100,6 +7348,27 @@ sub version {
return "version:$VERSION";
}
+sub get_usersession_config {
+ my ($dom,$name) = @_;
+ my ($usersessionconf,$cached)=&Apache::lonnet::is_cached_new($name,$dom);
+ if (defined($cached)) {
+ return $usersessionconf;
+ } else {
+ my %domconfig = &Apache::lonnet::get_dom('configuration',['usersessions'],$dom);
+ if (ref($domconfig{'usersessions'}) eq 'HASH') {
+ &Apache::lonnet::do_cache_new($name,$dom,$domconfig{'usersessions'},3600);
+ return $domconfig{'usersessions'};
+ }
+ }
+ return;
+}
+
+
+
+
+sub distro_and_arch {
+ return $dist.':'.$arch;
+}
# ----------------------------------- POD (plain old documentation, CPAN style)
@@ -7425,6 +7694,8 @@ Authen::Krb5
=head1 COREQUISITES
+none
+
=head1 OSNAMES
linux
@@ -7512,9 +7783,9 @@ or the CA's certificate in the call to l
is the textual reason this failed. Usual reasons:
=over 2
-
+
=item Apache config file for loncapa incorrect:
-
+
one of the variables
lonCertificateDirectory, lonnetCertificateAuthority, or lonnetCertificate
undefined or incorrect
@@ -7633,7 +7904,7 @@ Could not rewrite the
internal password file for a user
=item Result of password change for :
-
+
A unix password change for was attempted
and the pipe returned
@@ -7662,7 +7933,7 @@ lond has been asked to exit by its clien
client systemand is the full exit command sent to the server.
=item Red CRITICAL: ABNORMAL EXIT. child for server died through a crass with this error->[].
-
+
A lond child terminated. NOte that this termination can also occur when the
child receives the QUIT or DIE signals. is the process id of the child,
the host lond is working for, and the reason the child died
@@ -7746,7 +8017,7 @@ file when sent it's USR1 signal. That p
assumed to be hung in some un-fixable way.
=item Finished checking children
-
+
Master processs's USR1 processing is cojmplete.
=item (Red) CRITICAL: ------- Starting ------
@@ -7760,7 +8031,7 @@ Started a new child process for
connected to the child. This was as a result of a TCP/IP connection from a client.
=item Unable to determine who caller was, getpeername returned nothing
-
+
In child process initialization. either getpeername returned undef or
a zero sized object was returned. Processing continues, but in my opinion,
this should be cause for the child to exit.
@@ -7771,7 +8042,7 @@ In child process initialization. The pe
The client address is stored as "Unavailable" and processing continues.
=item (Yellow) INFO: Connection connection type =
-
+
In child initialization. A good connectionw as received from .
=over 2
@@ -7821,7 +8092,7 @@ The client ( is the peer's name
negotiated an SSL connection with this child process.
=item (Green) Successful insecure authentication with
-
+
The client has successfully negotiated an insecure connection withthe child process.
@@ -7835,5 +8106,7 @@ string.
=back
+=back
+
=cut