--- loncom/lonnet/perl/lonnet.pm 2018/08/09 14:04:35 1.1381
+++ loncom/lonnet/perl/lonnet.pm 2018/12/22 01:56:25 1.1396
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1381 2018/08/09 14:04:35 raeburn Exp $
+# $Id: lonnet.pm,v 1.1396 2018/12/22 01:56:25 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -73,7 +73,7 @@ package Apache::lonnet;
use strict;
use HTTP::Date;
use Image::Magick;
-
+use CGI::Cookie;
use Encode;
@@ -230,12 +230,19 @@ sub get_server_distarch {
}
sub get_servercerts_info {
- my ($lonhost,$context) = @_;
+ my ($lonhost,$hostname,$context) = @_;
+ return if ($lonhost eq '');
+ if ($hostname eq '') {
+ $hostname = &hostname($lonhost);
+ }
+ return if ($hostname eq '');
my ($rep,$uselocal);
- if (grep { $_ eq $lonhost } ¤t_machine_ids()) {
+ if ($context eq 'install') {
+ $uselocal = 1;
+ } elsif (grep { $_ eq $lonhost } ¤t_machine_ids()) {
$uselocal = 1;
}
- if (($context ne 'cgi') && ($uselocal)) {
+ if (($context ne 'cgi') && ($context ne 'install') && ($uselocal)) {
my $distro = (split(/\:/,&get_server_distarch($lonhost)))[0];
if ($distro eq '') {
$uselocal = 0;
@@ -250,16 +257,11 @@ sub get_servercerts_info {
}
}
if ($uselocal) {
- $rep = LONCAPA::Lond::server_certs(\%perlvar);
+ $rep = LONCAPA::Lond::server_certs(\%perlvar,$lonhost,$hostname);
} else {
$rep=&reply('servercerts',$lonhost);
}
my ($result,%returnhash);
- if (defined($lonhost)) {
- if (!defined(&hostname($lonhost))) {
- return;
- }
- }
if (($rep=~/^(refused|rejected|error)/) || ($rep eq 'con_lost') ||
($rep eq 'unknown_cmd')) {
$result = $rep;
@@ -456,8 +458,26 @@ sub reply {
unless (defined(&hostname($server))) { return 'no_such_host'; }
my $answer=subreply($cmd,$server);
if (($answer=~/^refused/) || ($answer=~/^rejected/)) {
- &logthis("WARNING:".
- " $cmd to $server returned $answer");
+ my $logged = $cmd;
+ if ($cmd =~ /^encrypt:([^:]+):/) {
+ my $subcmd = $1;
+ if (($subcmd eq 'auth') || ($subcmd eq 'passwd') ||
+ ($subcmd eq 'changeuserauth') || ($subcmd eq 'makeuser') ||
+ ($subcmd eq 'putdom') || ($subcmd eq 'autoexportgrades')) {
+ (undef,undef,my @rest) = split(/:/,$cmd);
+ if (($subcmd eq 'auth') || ($subcmd eq 'putdom')) {
+ splice(@rest,2,1,'Hidden');
+ } elsif ($subcmd eq 'passwd') {
+ splice(@rest,2,2,('Hidden','Hidden'));
+ } elsif (($subcmd eq 'changeuserauth') || ($subcmd eq 'makeuser') ||
+ ($subcmd eq 'autoexportgrades')) {
+ splice(@rest,3,1,'Hidden');
+ }
+ $logged = join(':',('encrypt:'.$subcmd,@rest));
+ }
+ }
+ &logthis("WARNING:".
+ " $logged to $server returned $answer");
}
return $answer;
}
@@ -709,6 +729,7 @@ sub check_for_valid_session {
if (!defined($disk_env{'user.name'})
|| !defined($disk_env{'user.domain'})) {
+ untie(%disk_env);
return undef;
}
@@ -721,6 +742,7 @@ sub check_for_valid_session {
$userhashref->{'ltiuri'} = $disk_env{'request.lti.uri'};
}
}
+ untie(%disk_env);
return $handle;
}
@@ -745,6 +767,37 @@ sub timed_flock {
}
}
+sub get_sessionfile_vars {
+ my ($handle,$lonidsdir,$storearr) = @_;
+ my %returnhash;
+ unless (ref($storearr) eq 'ARRAY') {
+ return %returnhash;
+ }
+ if (-l "$lonidsdir/$handle.id") {
+ my $link = readlink("$lonidsdir/$handle.id");
+ if ((-e $link) && ($link =~ m{^\Q$lonidsdir\E/(.+)\.id$})) {
+ $handle = $1;
+ }
+ }
+ if ((-e "$lonidsdir/$handle.id") &&
+ ($handle =~ /^($match_username)\_\d+\_($match_domain)\_(.+)$/)) {
+ my ($possuname,$possudom,$possuhome) = ($1,$2,$3);
+ if ((&domain($possudom) ne '') && (&homeserver($possuname,$possudom) eq $possuhome)) {
+ if (open(my $idf,'+<',"$lonidsdir/$handle.id")) {
+ flock($idf,LOCK_SH);
+ if (tie(my %disk_env,'GDBM_File',"$lonidsdir/$handle.id",
+ &GDBM_READER(),0640)) {
+ foreach my $item (@{$storearr}) {
+ $returnhash{$item} = $disk_env{$item};
+ }
+ untie(%disk_env);
+ }
+ }
+ }
+ }
+ return %returnhash;
+}
+
# ---------------------------------------------------------- Append Environment
sub appenv {
@@ -898,6 +951,7 @@ sub userload {
while ($filename=readdir(LONIDS)) {
next if ($filename eq '.' || $filename eq '..');
next if ($filename =~ /publicuser_\d+\.id/);
+ next if ($filename =~ /^[a-f0-9]+_linked\.id$/);
my ($mtime)=(stat($perlvar{'lonIDsDir'}.'/'.$filename))[9];
if ($curtime-$mtime < 1800) { $numusers++; }
}
@@ -1026,6 +1080,75 @@ sub find_existing_session {
return;
}
+# check if user's browser sent load balancer cookie and server still has session
+# and is not overloaded.
+sub check_for_balancer_cookie {
+ my ($r,$update_mtime) = @_;
+ my ($otherserver,$cookie);
+ my %cookies=CGI::Cookie->parse($r->header_in('Cookie'));
+ if (exists($cookies{'balanceID'})) {
+ my $balid = $cookies{'balanceID'};
+ $cookie=&LONCAPA::clean_handle($balid->value);
+ my $balancedir=$r->dir_config('lonBalanceDir');
+ if ((-d $balancedir) && (-e "$balancedir/$cookie.id")) {
+ if ($cookie =~ /^($match_domain)_($match_username)_[a-f0-9]+$/) {
+ my ($possudom,$possuname) = ($1,$2);
+ my $has_session = 0;
+ if ((&domain($possudom) ne '') &&
+ (&homeserver($possuname,$possudom) ne 'no_host')) {
+ my $try_server;
+ my $opened = open(my $idf,'+<',"$balancedir/$cookie.id");
+ if ($opened) {
+ flock($idf,LOCK_SH);
+ while (my $line = <$idf>) {
+ chomp($line);
+ if (&hostname($line) ne '') {
+ $try_server = $line;
+ last;
+ }
+ }
+ close($idf);
+ if (($try_server) &&
+ (&has_user_session($try_server,$possudom,$possuname))) {
+ my $lowest_load = 30000;
+ ($otherserver,$lowest_load) =
+ &compare_server_load($try_server,undef,$lowest_load);
+ if ($otherserver ne '' && $lowest_load < 100) {
+ $has_session = 1;
+ } else {
+ undef($otherserver);
+ }
+ }
+ }
+ }
+ if ($has_session) {
+ if ($update_mtime) {
+ my $atime = my $mtime = time;
+ utime($atime,$mtime,"$balancedir/$cookie.id");
+ }
+ } else {
+ unlink("$balancedir/$cookie.id");
+ }
+ }
+ }
+ }
+ return ($otherserver,$cookie);
+}
+
+sub delbalcookie {
+ my ($cookie,$balancer) =@_;
+ if ($cookie =~ /^($match_domain)\_($match_username)\_[a-f0-9]{32}$/) {
+ my ($udom,$uname) = ($1,$2);
+ my $uprimary_id = &domain($udom,'primary');
+ my $uintdom = &internet_dom($uprimary_id);
+ my $intdom = &internet_dom($balancer);
+ my $serverhomedom = &host_domain($balancer);
+ if (($uintdom ne '') && ($uintdom eq $intdom)) {
+ return &reply("delbalcookie:$cookie",$balancer);
+ }
+ }
+}
+
# -------------------------------- ask if server already has a session for user
sub has_user_session {
my ($lonid,$udom,$uname) = @_;
@@ -1061,7 +1184,7 @@ sub choose_server {
if (ref($balancers) eq 'HASH') {
next if (exists($balancers->{$lonhost}));
}
- }
+ }
my $loginvia;
if ($checkloginvia) {
$loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost};
@@ -1363,7 +1486,7 @@ sub get_lonbalancer_config {
sub check_loadbalancing {
my ($uname,$udom,$caller) = @_;
my ($is_balancer,$currtargets,$currrules,$dom_in_use,$homeintdom,
- $rule_in_effect,$offloadto,$otherserver);
+ $rule_in_effect,$offloadto,$otherserver,$setcookie,$dom_balancers);
my $lonhost = $perlvar{'lonHostID'};
my @hosts = ¤t_machine_ids();
my $uprimary_id = &Apache::lonnet::domain($udom,'primary');
@@ -1390,7 +1513,7 @@ sub check_loadbalancing {
}
}
if (ref($result) eq 'HASH') {
- ($is_balancer,$currtargets,$currrules) =
+ ($is_balancer,$currtargets,$currrules,$setcookie,$dom_balancers) =
&check_balancer_result($result,@hosts);
if ($is_balancer) {
if (ref($currrules) eq 'HASH') {
@@ -1451,7 +1574,7 @@ sub check_loadbalancing {
}
}
if (ref($result) eq 'HASH') {
- ($is_balancer,$currtargets,$currrules) =
+ ($is_balancer,$currtargets,$currrules,$setcookie,$dom_balancers) =
&check_balancer_result($result,@hosts);
if ($is_balancer) {
if (ref($currrules) eq 'HASH') {
@@ -1517,20 +1640,22 @@ sub check_loadbalancing {
$is_balancer = 0;
if ($uname ne '' && $udom ne '') {
if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) {
-
- &appenv({'user.loadbalexempt' => $lonhost,
+ &appenv({'user.loadbalexempt' => $lonhost,
'user.loadbalcheck.time' => time});
}
}
}
}
+ unless ($homeintdom) {
+ undef($setcookie);
+ }
}
- return ($is_balancer,$otherserver);
+ return ($is_balancer,$otherserver,$setcookie,$offloadto,$dom_balancers);
}
sub check_balancer_result {
my ($result,@hosts) = @_;
- my ($is_balancer,$currtargets,$currrules);
+ my ($is_balancer,$currtargets,$currrules,$setcookie,$dom_balancers);
if (ref($result) eq 'HASH') {
if ($result->{'lonhost'} ne '') {
my $currbalancer = $result->{'lonhost'};
@@ -1539,19 +1664,24 @@ sub check_balancer_result {
$currtargets = $result->{'targets'};
$currrules = $result->{'rules'};
}
+ $dom_balancers = $currbalancer;
} else {
- foreach my $key (keys(%{$result})) {
- if (($key ne '') && (grep(/^\Q$key\E$/,@hosts)) &&
- (ref($result->{$key}) eq 'HASH')) {
- $is_balancer = 1;
- $currrules = $result->{$key}{'rules'};
- $currtargets = $result->{$key}{'targets'};
- last;
+ if (keys(%{$result})) {
+ foreach my $key (keys(%{$result})) {
+ if (($key ne '') && (grep(/^\Q$key\E$/,@hosts)) &&
+ (ref($result->{$key}) eq 'HASH')) {
+ $is_balancer = 1;
+ $currrules = $result->{$key}{'rules'};
+ $currtargets = $result->{$key}{'targets'};
+ $setcookie = $result->{$key}{'cookie'};
+ last;
+ }
}
+ $dom_balancers = join(',',sort(keys(%{$result})));
}
}
}
- return ($is_balancer,$currtargets,$currrules);
+ return ($is_balancer,$currtargets,$currrules,$setcookie,$dom_balancers);
}
sub get_loadbalancer_targets {
@@ -1629,7 +1759,7 @@ sub trusted_domains {
if (&domain($calldom) eq '') {
return ($trusted,$untrusted);
}
- unless ($cmdtype =~ /^(content|shared|enroll|coaurem|domroles|catalog|reqcrs|msg)$/) {
+ unless ($cmdtype =~ /^(content|shared|enroll|coaurem|othcoau|domroles|catalog|reqcrs|msg)$/) {
return ($trusted,$untrusted);
}
my $callprimary = &domain($calldom,'primary');
@@ -1651,6 +1781,7 @@ sub trusted_domains {
map { $possexc{$_} = 1; } @{$trustconfig->{$cmdtype}->{'exc'}};
}
if (ref($trustconfig->{$cmdtype}->{'inc'}) eq 'ARRAY') {
+ $possinc{$intcalldom} = 1;
map { $possinc{$_} = 1; } @{$trustconfig->{$cmdtype}->{'inc'}};
}
}
@@ -1685,12 +1816,12 @@ sub trusted_domains {
}
foreach my $exc (@allexc) {
if (ref($doms_by_intdom{$exc}) eq 'ARRAY') {
- $untrusted = $doms_by_intdom{$exc};
+ push(@{$untrusted},@{$doms_by_intdom{$exc}});
}
}
foreach my $inc (@allinc) {
if (ref($doms_by_intdom{$inc}) eq 'ARRAY') {
- $trusted = $doms_by_intdom{$inc};
+ push(@{$trusted},@{$doms_by_intdom{$inc}});
}
}
}
@@ -3197,7 +3328,17 @@ sub ssi {
$request->header(Cookie => $ENV{'HTTP_COOKIE'});
my $lonhost = $perlvar{'lonHostID'};
- my $response= &LONCAPA::LWPReq::makerequest($lonhost,$request,'',\%perlvar);
+ my $islocal;
+ if (($env{'request.course.id'}) &&
+ ($form{'grade_courseid'} eq $env{'request.course.id'}) &&
+ ($form{'grade_username'} ne '') && ($form{'grade_domain'} ne '') &&
+ ($form{'grade_symb'} ne '') &&
+ (&Apache::lonnet::allowed('mgr',$env{'request.course.id'}.
+ ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
+ $islocal = 1;
+ }
+ my $response= &LONCAPA::LWPReq::makerequest($lonhost,$request,'',\%perlvar,
+ '','','',$islocal);
if (wantarray) {
return ($response->content, $response);
@@ -5231,7 +5372,12 @@ sub set_first_access {
}
$cachedkey='';
my $firstaccess=&get_first_access($type,$symb,$map);
- if (!$firstaccess) {
+ if ($firstaccess) {
+ &logthis("First access time already set ($firstaccess) when attempting ".
+ "to set new value (type: $type, extent: $res) for $uname:$udom ".
+ "in $courseid");
+ return 'already_set';
+ } else {
my $start = time;
my $putres = &put('firstaccesstimes',{"$courseid\0$res"=>$start},
$udom,$uname);
@@ -5247,6 +5393,9 @@ sub set_first_access {
if (($cachedtime) && (abs($start-$cachedtime) < 5)) {
$cachedtimes{"$courseid\0$res"} = $start;
}
+ } elsif ($putres ne 'refused') {
+ &logthis("Result: $putres when attempting to set first access time ".
+ "(type: $type, extent: $res) for $uname:$udom in $courseid");
}
return $putres;
}
@@ -10045,7 +10194,7 @@ sub is_course {
my $uhome=&homeserver($cnum,$cdom);
my $iscourse;
if (grep { $_ eq $uhome } current_machine_ids()) {
- $iscourse = &Lond::is_course($cdom,$cnum);
+ $iscourse = &LONCAPA::Lond::is_course($cdom,$cnum);
} else {
my $hashid = $cdom.':'.$cnum;
($iscourse,my $cached) = &is_cached_new('iscourse',$hashid);