--- loncom/lonnet/perl/lonnet.pm 2023/10/06 02:48:36 1.1172.2.146.2.16 +++ loncom/lonnet/perl/lonnet.pm 2020/10/15 19:17:40 1.1429 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1172.2.146.2.16 2023/10/06 02:48:36 raeburn Exp $ +# $Id: lonnet.pm,v 1.1429 2020/10/15 19:17:40 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -71,11 +71,12 @@ delayed. package Apache::lonnet; use strict; -use LWP::UserAgent(); use HTTP::Date; use Image::Magick; use CGI::Cookie; +use Encode; + use vars qw(%perlvar %spareid %pr %prp $memcache %packagetab $tmpdir $deftex $_64bit %env %protocol %loncaparevs %serverhomeIDs %needsrelease %managerstab $passwdmin); @@ -95,12 +96,11 @@ use Cache::Memcached; use Digest::MD5; use Math::Random; use File::MMagic; -use Net::CIDR; -use Sys::Hostname::FQDN(); use LONCAPA qw(:DEFAULT :match); use LONCAPA::Configuration; use LONCAPA::lonmetadata; use LONCAPA::Lond; +use LONCAPA::LWPReq; use LONCAPA::transliterate; use File::Copy; @@ -113,6 +113,7 @@ require Exporter; our @ISA = qw (Exporter); our @EXPORT = qw(%env); + # ------------------------------------ Logging (parameters, docs, slots, roles) { my $logid; @@ -127,20 +128,19 @@ our @EXPORT = qw(%env); $logid ++; my $now = time(); my $id=$now.'00000'.$$.'00000'.$logid; - my $ip = &get_requestor_ip(); - my $logentry = { - $id => { - 'exe_uname' => $env{'user.name'}, - 'exe_udom' => $env{'user.domain'}, - 'exe_time' => $now, - 'exe_ip' => $ip, - 'delflag' => $delflag, - 'logentry' => $storehash, - 'uname' => $uname, - 'udom' => $udom, - } + my $logentry = { + $id => { + 'exe_uname' => $env{'user.name'}, + 'exe_udom' => $env{'user.domain'}, + 'exe_time' => $now, + 'exe_ip' => $ENV{'REMOTE_ADDR'}, + 'delflag' => $delflag, + 'logentry' => $storehash, + 'uname' => $uname, + 'udom' => $udom, + } }; - return &put('nohist_'.$hash_name,$logentry,$cdom,$cnum); + return &put('nohist_'.$hash_name,$logentry,$cdom,$cnum); } } @@ -185,7 +185,7 @@ sub create_connection { Type => SOCK_STREAM, Timeout => 10); return 0 if (!$client); - print $client (join(':',$hostname,$lonid,&machine_ids($hostname))."\n"); + print $client (join(':',$hostname,$lonid,&machine_ids($hostname),$loncaparevs{$lonid})."\n"); my $result = <$client>; chomp($result); return 1 if ($result eq 'done'); @@ -230,6 +230,54 @@ sub get_server_distarch { return; } +sub get_servercerts_info { + my ($lonhost,$hostname,$context) = @_; + return if ($lonhost eq ''); + if ($hostname eq '') { + $hostname = &hostname($lonhost); + } + return if ($hostname eq ''); + my ($rep,$uselocal); + if ($context eq 'install') { + $uselocal = 1; + } elsif (grep { $_ eq $lonhost } ¤t_machine_ids()) { + $uselocal = 1; + } + if (($context ne 'cgi') && ($context ne 'install') && ($uselocal)) { + my $distro = (split(/\:/,&get_server_distarch($lonhost)))[0]; + if ($distro eq '') { + $uselocal = 0; + } elsif ($distro =~ /^(?:centos|redhat|scientific)(\d+)$/) { + if ($1 < 6) { + $uselocal = 0; + } + } elsif ($distro =~ /^(?:sles)(\d+)$/) { + if ($1 < 12) { + $uselocal = 0; + } + } + } + if ($uselocal) { + $rep = LONCAPA::Lond::server_certs(\%perlvar,$lonhost,$hostname); + } else { + $rep=&reply('servercerts',$lonhost); + } + my ($result,%returnhash); + if (($rep=~/^(refused|rejected|error)/) || ($rep eq 'con_lost') || + ($rep eq 'unknown_cmd')) { + $result = $rep; + } else { + $result = 'ok'; + my @pairs=split(/\&/,$rep); + foreach my $item (@pairs) { + my ($key,$value)=split(/=/,$item,2); + my $what = &unescape($key); + $returnhash{$what}=&thaw_unescape($value); + } + } + return ($result,\%returnhash); +} + sub get_server_loncaparev { my ($dom,$lonhost,$ignore_cache,$caller) = @_; if (defined($lonhost)) { @@ -264,14 +312,12 @@ sub get_server_loncaparev { $answer = &reply('serverloncaparev',$lonhost); if (($answer eq 'unknown_cmd') || ($answer eq 'con_lost')) { if ($caller eq 'loncron') { - my $ua=new LWP::UserAgent; - $ua->timeout(4); my $hostname = &hostname($lonhost); my $protocol = $protocol{$lonhost}; $protocol = 'http' if ($protocol ne 'https'); my $url = $protocol.'://'.$hostname.'/adm/about.html'; my $request=new HTTP::Request('GET',$url); - my $response=$ua->request($request); + my $response=&LONCAPA::LWPReq::makerequest($lonhost,$request,'',\%perlvar,4,1); unless ($response->is_error()) { my $content = $response->content; if ($content =~ /

VERSION\:\s*([\w.\-]+)<\/p>/) { @@ -362,64 +408,8 @@ sub remote_devalidate_cache { my $items; return unless (ref($cachekeys) eq 'ARRAY'); my $cachestr = join('&',@{$cachekeys}); - return &reply('devalidatecache:'.&escape($cachestr),$lonhost); -} - -sub sign_lti { - my ($cdom,$cnum,$crsdef,$type,$context,$url,$ltinum,$keynum,$paramsref,$inforef) = @_; - my $chome; - if (&domain($cdom) ne '') { - if ($crsdef) { - $chome = &homeserver($cnum,$cdom); - } else { - $chome = &domain($cdom,'primary'); - } - } - if ($cdom && $chome && ($chome ne 'no_host')) { - if ((ref($paramsref) eq 'HASH') && - (ref($inforef) eq 'HASH')) { - my $rep; - if (grep { $_ eq $chome } ¤t_machine_ids()) { - # domain information is hosted on this machine - $rep = - &LONCAPA::Lond::sign_lti_payload($cdom,$cnum,$crsdef,$type, - $context,$url,$ltinum,$keynum, - $perlvar{'lonVersion'}, - $paramsref,$inforef); - if (ref($rep) eq 'HASH') { - return ('ok',$rep); - } - } else { - my ($escurl,$params,$info); - $escurl = &escape($url); - if (ref($paramsref) eq 'HASH') { - $params = &freeze_escape($paramsref); - } - if (ref($inforef) eq 'HASH') { - $info = &freeze_escape($inforef); - } - $rep=&reply("encrypt:signlti:$cdom:$cnum:$crsdef:$type:$context:$escurl:$ltinum:$keynum:$params:$info",$chome); - } - if (($rep eq '') || ($rep =~ /^con_lost|error|no_such_host|unknown_cmd/i)) { - return (); - } elsif (($inforef->{'respfmt'} eq 'to_post_body') || - ($inforef->{'respfmt'} eq 'to_authorization_header')) { - return ('ok',$rep); - } else { - my %returnhash; - foreach my $item (split(/\&/,$rep)) { - my ($name,$value)=split(/\=/,$item); - $returnhash{&unescape($name)}=&thaw_unescape($value); - } - return('ok',\%returnhash); - } - } else { - return (); - } - } else { - return (); - &logthis("sign_lti failed - no homeserver and/or domain ($cdom) ($chome)"); - } + my $response = &reply('devalidatecache:'.&escape($cachestr),$lonhost); + return $response; } # -------------------------------------------------- Non-critical communication @@ -451,7 +441,7 @@ sub subreply { } else { &create_connection(&hostname($server),$server); } - sleep(0.1); # Try again later if failed connection. + sleep(0.1); # Try again later if failed connection. } my $answer; if ($client) { @@ -475,15 +465,14 @@ sub reply { my $subcmd = $1; if (($subcmd eq 'auth') || ($subcmd eq 'passwd') || ($subcmd eq 'changeuserauth') || ($subcmd eq 'makeuser') || - ($subcmd eq 'putdom') || ($subcmd eq 'autoexportgrades') || - ($subcmd eq 'put')) { + ($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') || ($subcmd eq 'put')) { + ($subcmd eq 'autoexportgrades')) { splice(@rest,3,1,'Hidden'); } $logged = join(':',('encrypt:'.$subcmd,@rest)); @@ -525,7 +514,7 @@ sub reconlonc { &logthis("lonc at pid $loncpid responding, sending USR1"); kill USR1 => $loncpid; sleep 1; - } else { + } else { &logthis( "WARNING:". " lonc at pid $loncpid not responding, giving up"); @@ -720,7 +709,7 @@ sub check_for_valid_session { } } if (!-e "$lonidsdir/$handle.id") { - if ((ref($domref)) && ($name eq 'lonID') && + if ((ref($domref)) && ($name eq 'lonID') && ($handle =~ /^($match_username)\_\d+\_($match_domain)\_(.+)$/)) { my ($possuname,$possudom,$possuhome) = ($1,$2,$3); if ((&domain($possudom) ne '') && (&homeserver($possuname,$possudom) eq $possuhome)) { @@ -749,9 +738,6 @@ sub check_for_valid_session { if (ref($userhashref) eq 'HASH') { $userhashref->{'name'} = $disk_env{'user.name'}; $userhashref->{'domain'} = $disk_env{'user.domain'}; - if ($disk_env{'request.role'}) { - $userhashref->{'role'} = $disk_env{'request.role'}; - } $userhashref->{'lti'} = $disk_env{'request.lti.login'}; if ($userhashref->{'lti'}) { $userhashref->{'ltitarget'} = $disk_env{'request.lti.target'}; @@ -985,7 +971,7 @@ sub userload { # ------------------------------ Find server with least workload from spare.tab sub spareserver { - my ($r,$loadpercent,$userloadpercent,$want_server_name,$udom) = @_; + my ($loadpercent,$userloadpercent,$want_server_name,$udom) = @_; my $spare_server; if ($userloadpercent !~ /\d/) { $userloadpercent=0; } my $lowest_load=($loadpercent > $userloadpercent) ? $loadpercent @@ -1030,8 +1016,6 @@ sub spareserver { if ($protocol{$spare_server} eq 'https') { $protocol = $protocol{$spare_server}; } - my $alias = &Apache::lonnet::use_proxy_alias($r,$spare_server); - $hostname = $alias if ($alias ne ''); $spare_server = $protocol.'://'.$hostname; } } @@ -1111,7 +1095,6 @@ sub delusersession { return; } - # check if user's browser sent load balancer cookie and server still has session # and is not overloaded. sub check_for_balancer_cookie { @@ -1167,21 +1150,6 @@ sub check_for_balancer_cookie { return ($otherserver,$cookie); } -sub updatebalcookie { - my ($cookie,$balancer,$lastentry)=@_; - 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('updatebalcookie:'.&escape($cookie).':'.&escape($lastentry),$balancer); - } - } - return; -} - sub delbalcookie { my ($cookie,$balancer) =@_; if ($cookie =~ /^($match_domain)\_($match_username)\_[a-f0-9]{32}$/) { @@ -1191,7 +1159,7 @@ sub delbalcookie { my $intdom = &internet_dom($balancer); my $serverhomedom = &host_domain($balancer); if (($uintdom ne '') && ($uintdom eq $intdom)) { - return &reply('delbalcookie:'.&escape($cookie),$balancer); + return &reply("delbalcookie:$cookie",$balancer); } } } @@ -1227,12 +1195,12 @@ sub choose_server { } } foreach my $lonhost (keys(%servers)) { - my $loginvia; if ($skiploadbal) { if (ref($balancers) eq 'HASH') { next if (exists($balancers->{$lonhost})); } } + my $loginvia; if ($checkloginvia) { $loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost}; if ($loginvia) { @@ -1331,7 +1299,7 @@ sub changepass { sub queryauthenticate { my ($uname,$udom)=@_; my $uhome=&homeserver($uname,$udom); - if ((!$uhome) || ($uhome eq 'no_host')) { + if (!$uhome) { &logthis("User $uname at $udom is unknown when looking for authentication mechanism"); return 'no_host'; } @@ -1380,35 +1348,12 @@ sub authenticate { } if ($answer eq 'non_authorized') { &logthis("User $uname at $udom rejected by $uhome"); - return 'no_host'; + return 'no_host'; } &logthis("User $uname at $udom threw error $answer when checking authentication mechanism"); return 'no_host'; } -sub can_switchserver { - my ($udom,$home) = @_; - my ($canswitch,@intdoms); - my $internet_names = &get_internet_names($home); - if (ref($internet_names) eq 'ARRAY') { - @intdoms = @{$internet_names}; - } - my $uint_dom = &internet_dom(&domain($udom,'primary')); - if ($uint_dom ne '' && grep(/^\Q$uint_dom\E$/,@intdoms)) { - $canswitch = 1; - } else { - my $serverhomeID = &get_server_homeID(&hostname($home)); - my $serverhomedom = &host_domain($serverhomeID); - my %defdomdefaults = &get_domain_defaults($serverhomedom); - my %udomdefaults = &get_domain_defaults($udom); - my $remoterev = &get_server_loncaparev('',$home); - $canswitch = &can_host_session($udom,$home,$remoterev, - $udomdefaults{'remotesessions'}, - $defdomdefaults{'hostedsessions'}); - } - return $canswitch; -} - sub can_host_session { my ($udom,$lonhost,$remoterev,$remotesessions,$hostedsessions) = @_; my $canhost = 1; @@ -1483,15 +1428,6 @@ sub spare_can_host { $canhost = 0; } } - if ($canhost) { - if (ref($defdomdefaults{'offloadoth'}) eq 'HASH') { - if ($defdomdefaults{'offloadoth'}{$try_server}) { - unless (&shared_institution($udom,$try_server)) { - $canhost = 0; - } - } - } - } if (($canhost) && ($uint_dom)) { my @intdoms; my $internet_names = &get_internet_names($try_server); @@ -1590,14 +1526,14 @@ 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,$setcookie); + $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'); my $uintdom = &Apache::lonnet::internet_dom($uprimary_id); my $intdom = &Apache::lonnet::internet_dom($lonhost); my $serverhomedom = &host_domain($lonhost); - my $domneedscache; + my $domneedscache; my $cachetime = 60*60*24; if (($uintdom ne '') && ($uintdom eq $intdom)) { @@ -1617,7 +1553,7 @@ sub check_loadbalancing { } } if (ref($result) eq 'HASH') { - ($is_balancer,$currtargets,$currrules,$setcookie) = + ($is_balancer,$currtargets,$currrules,$setcookie,$dom_balancers) = &check_balancer_result($result,@hosts); if ($is_balancer) { if (ref($currrules) eq 'HASH') { @@ -1678,7 +1614,7 @@ sub check_loadbalancing { } } if (ref($result) eq 'HASH') { - ($is_balancer,$currtargets,$currrules,$setcookie) = + ($is_balancer,$currtargets,$currrules,$setcookie,$dom_balancers) = &check_balancer_result($result,@hosts); if ($is_balancer) { if (ref($currrules) eq 'HASH') { @@ -1710,7 +1646,7 @@ sub check_loadbalancing { if ($domneedscache) { &do_cache_new('loadbalancing',$domneedscache,$is_balancer,$cachetime); } - if (($is_balancer) && ($caller ne 'switchserver')) { + if ($is_balancer) { my $lowest_load = 30000; if (ref($offloadto) eq 'HASH') { if (ref($offloadto->{'primary'}) eq 'ARRAY') { @@ -1750,16 +1686,16 @@ sub check_loadbalancing { } } } + unless ($homeintdom) { + undef($setcookie); + } } - if (($is_balancer) && (!$homeintdom)) { - undef($setcookie); - } - return ($is_balancer,$otherserver,$setcookie); + return ($is_balancer,$otherserver,$setcookie,$offloadto,$dom_balancers); } sub check_balancer_result { my ($result,@hosts) = @_; - my ($is_balancer,$currtargets,$currrules,$setcookie); + my ($is_balancer,$currtargets,$currrules,$setcookie,$dom_balancers); if (ref($result) eq 'HASH') { if ($result->{'lonhost'} ne '') { my $currbalancer = $result->{'lonhost'}; @@ -1768,20 +1704,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'}; - $setcookie = $result->{$key}{'cookie'}; - 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,$setcookie); + return ($is_balancer,$currtargets,$currrules,$setcookie,$dom_balancers); } sub get_loadbalancer_targets { @@ -1853,6 +1793,101 @@ sub internet_dom_servers { return %uniqservers; } +sub trusted_domains { + my ($cmdtype,$calldom) = @_; + my ($trusted,$untrusted); + if (&domain($calldom) eq '') { + return ($trusted,$untrusted); + } + unless ($cmdtype =~ /^(content|shared|enroll|coaurem|othcoau|domroles|catalog|reqcrs|msg)$/) { + return ($trusted,$untrusted); + } + my $callprimary = &domain($calldom,'primary'); + my $intcalldom = &Apache::lonnet::internet_dom($callprimary); + if ($intcalldom eq '') { + return ($trusted,$untrusted); + } + + my ($trustconfig,$cached)=&Apache::lonnet::is_cached_new('trust',$calldom); + unless (defined($cached)) { + my %domconfig = &Apache::lonnet::get_dom('configuration',['trust'],$calldom); + &Apache::lonnet::do_cache_new('trust',$calldom,$domconfig{'trust'},3600); + $trustconfig = $domconfig{'trust'}; + } + if (ref($trustconfig)) { + my (%possexc,%possinc,@allexc,@allinc); + if (ref($trustconfig->{$cmdtype}) eq 'HASH') { + if (ref($trustconfig->{$cmdtype}->{'exc'}) eq 'ARRAY') { + map { $possexc{$_} = 1; } @{$trustconfig->{$cmdtype}->{'exc'}}; + } + if (ref($trustconfig->{$cmdtype}->{'inc'}) eq 'ARRAY') { + $possinc{$intcalldom} = 1; + map { $possinc{$_} = 1; } @{$trustconfig->{$cmdtype}->{'inc'}}; + } + } + if (keys(%possexc)) { + if (keys(%possinc)) { + foreach my $key (sort(keys(%possexc))) { + next if ($key eq $intcalldom); + unless ($possinc{$key}) { + push(@allexc,$key); + } + } + } else { + @allexc = sort(keys(%possexc)); + } + } + if (keys(%possinc)) { + $possinc{$intcalldom} = 1; + @allinc = sort(keys(%possinc)); + } + if ((@allexc > 0) || (@allinc > 0)) { + my %doms_by_intdom; + my %allintdoms = &all_host_intdom(); + my %alldoms = &all_host_domain(); + foreach my $key (%allintdoms) { + if (ref($doms_by_intdom{$allintdoms{$key}}) eq 'ARRAY') { + unless (grep(/^\Q$alldoms{$key}\E$/,@{$doms_by_intdom{$allintdoms{$key}}})) { + push(@{$doms_by_intdom{$allintdoms{$key}}},$alldoms{$key}); + } + } else { + $doms_by_intdom{$allintdoms{$key}} = [$alldoms{$key}]; + } + } + foreach my $exc (@allexc) { + if (ref($doms_by_intdom{$exc}) eq 'ARRAY') { + push(@{$untrusted},@{$doms_by_intdom{$exc}}); + } + } + foreach my $inc (@allinc) { + if (ref($doms_by_intdom{$inc}) eq 'ARRAY') { + push(@{$trusted},@{$doms_by_intdom{$inc}}); + } + } + } + } + return ($trusted,$untrusted); +} + +sub will_trust { + my ($cmdtype,$domain,$possdom) = @_; + return 1 if ($domain eq $possdom); + my ($trustedref,$untrustedref) = &trusted_domains($cmdtype,$possdom); + my $willtrust; + if ((ref($trustedref) eq 'ARRAY') && (@{$trustedref} > 0)) { + if (grep(/^\Q$domain\E$/,@{$trustedref})) { + $willtrust = 1; + } + } elsif ((ref($untrustedref) eq 'ARRAY') && (@{$untrustedref} > 0)) { + unless (grep(/^\Q$domain\E$/,@{$untrustedref})) { + $willtrust = 1; + } + } else { + $willtrust = 1; + } + return $willtrust; +} + # ---------------------- Find the homebase for a user from domain's lib servers my %homecache; @@ -1878,17 +1913,33 @@ sub homeserver { return 'no_host'; } -# ------------------------------------- Find the usernames behind a list of IDs +# ----- Find the usernames behind a list of student/employee IDs or clicker IDs sub idget { - my ($udom,@ids)=@_; + my ($udom,$idsref,$namespace)=@_; my %returnhash=(); + my @ids=(); + if (ref($idsref) eq 'ARRAY') { + @ids = @{$idsref}; + } else { + return %returnhash; + } + if ($namespace eq '') { + $namespace = 'ids'; + } my %servers = &get_servers($udom,'library'); foreach my $tryserver (keys(%servers)) { my $idlist=join('&', map { &escape($_); } @ids); - $idlist=~tr/A-Z/a-z/; - my $reply=&reply("idget:$udom:".$idlist,$tryserver); + if ($namespace eq 'ids') { + $idlist=~tr/A-Z/a-z/; + } + my $reply; + if ($namespace eq 'ids') { + $reply=&reply("idget:$udom:".$idlist,$tryserver); + } else { + $reply=&reply("getdom:$udom:$namespace:$idlist",$tryserver); + } my @answer=(); if (($reply ne 'con_lost') && ($reply!~/^error\:/)) { @answer=split(/\&/,$reply); @@ -1897,9 +1948,9 @@ sub idget { for ($i=0;$i<=$#ids;$i++) { if ($answer[$i]) { $returnhash{$ids[$i]}=&unescape($answer[$i]); - } + } } - } + } return %returnhash; } @@ -1914,60 +1965,141 @@ sub idrget { return %returnhash; } -# ------------------------------- Store away a list of names and associated IDs +# Store away a list of names and associated student/employee IDs or clicker IDs sub idput { - my ($udom,%ids)=@_; + my ($udom,$idsref,$uhom,$namespace)=@_; my %servers=(); + my %ids=(); + my %byid = (); + if (ref($idsref) eq 'HASH') { + %ids=%{$idsref}; + } + if ($namespace eq '') { + $namespace = 'ids'; + } foreach my $uname (keys(%ids)) { &cput('environment',{'id'=>$ids{$uname}},$udom,$uname); - my $uhom=&homeserver($uname,$udom); + if ($uhom eq '') { + $uhom=&homeserver($uname,$udom); + } if ($uhom ne 'no_host') { - my $id=&escape($ids{$uname}); - $id=~tr/A-Z/a-z/; my $esc_unam=&escape($uname); - if ($servers{$uhom}) { - $servers{$uhom}.='&'.$id.'='.$esc_unam; + if ($namespace eq 'ids') { + my $id=&escape($ids{$uname}); + $id=~tr/A-Z/a-z/; + my $esc_unam=&escape($uname); + $servers{$uhom}.=$id.'='.$esc_unam.'&'; } else { - $servers{$uhom}=$id.'='.$esc_unam; + my @currids = split(/,/,$ids{$uname}); + foreach my $id (@currids) { + $byid{$uhom}{$id} .= $uname.','; + } + } + } + } + if ($namespace eq 'clickers') { + foreach my $server (keys(%byid)) { + if (ref($byid{$server}) eq 'HASH') { + foreach my $id (keys(%{$byid{$server}})) { + $byid{$server} =~ s/,$//; + $servers{$uhom}.=&escape($id).'='.&escape($byid{$server}).'&'; + } } } } foreach my $server (keys(%servers)) { - &critical('idput:'.$udom.':'.$servers{$server},$server); + $servers{$server} =~ s/\&$//; + if ($namespace eq 'ids') { + &critical('idput:'.$udom.':'.$servers{$server},$server); + } else { + &critical('updateclickers:'.$udom.':add:'.$servers{$server},$server); + } } } -# ---------------------------------------- Delete unwanted IDs from ids.db file +# ------------- Delete unwanted student/employee IDs or clicker IDs from domain sub iddel { - my ($udom,$idshashref,$uhome)=@_; + my ($udom,$idshashref,$uhome,$namespace)=@_; my %result=(); - unless (ref($idshashref) eq 'HASH') { + my %ids=(); + my %byid = (); + if (ref($idshashref) eq 'HASH') { + %ids=%{$idshashref}; + } else { return %result; } + if ($namespace eq '') { + $namespace = 'ids'; + } my %servers=(); - while (my ($id,$uname) = each(%{$idshashref})) { - my $uhom; - if ($uhome) { - $uhom = $uhome; - } else { - $uhom=&homeserver($uname,$udom); - } - if ($uhom ne 'no_host') { - if ($servers{$uhom}) { + while (my ($id,$unamestr) = each(%ids)) { + if ($namespace eq 'ids') { + my $uhom = $uhome; + if ($uhom eq '') { + $uhom=&homeserver($unamestr,$udom); + } + if ($uhom ne 'no_host') { $servers{$uhom}.='&'.&escape($id); - } else { - $servers{$uhom}=&escape($id); + } + } else { + my @curritems = split(/,/,$ids{$id}); + foreach my $uname (@curritems) { + my $uhom = $uhome; + if ($uhom eq '') { + $uhom=&homeserver($uname,$udom); + } + if ($uhom ne 'no_host') { + $byid{$uhom}{$id} .= $uname.','; + } + } + } + } + if ($namespace eq 'clickers') { + foreach my $server (keys(%byid)) { + if (ref($byid{$server}) eq 'HASH') { + foreach my $id (keys(%{$byid{$server}})) { + $byid{$server}{$id} =~ s/,$//; + $servers{$server}.=&escape($id).'='.&escape($byid{$server}{$id}).'&'; + } } } } foreach my $server (keys(%servers)) { - $result{$server} = &critical('iddel:'.$udom.':'.$servers{$server},$uhome); + $servers{$server} =~ s/\&$//; + if ($namespace eq 'ids') { + $result{$server} = &critical('iddel:'.$udom.':'.$servers{$server},$uhome); + } elsif ($namespace eq 'clickers') { + $result{$server} = &critical('updateclickers:'.$udom.':del:'.$servers{$server},$server); + } } return %result; } +# ----- Update clicker ID-to-username look-ups in clickers.db on library server + +sub updateclickers { + my ($udom,$action,$idshashref,$uhome,$critical) = @_; + my %clickers; + if (ref($idshashref) eq 'HASH') { + %clickers=%{$idshashref}; + } else { + return; + } + my $items=''; + foreach my $item (keys(%clickers)) { + $items.=&escape($item).'='.&escape($clickers{$item}).'&'; + } + $items=~s/\&$//; + my $request = "updateclickers:$udom:$action:$items"; + if ($critical) { + return &critical($request,$uhome); + } else { + return &reply($request,$uhome); + } +} + # ------------------------------dump from db file owned by domainconfig user sub dump_dom { my ($namespace, $udom, $regexp) = @_; @@ -1982,7 +2114,7 @@ sub dump_dom { # ------------------------------------------ get items from domain db files sub get_dom { - my ($namespace,$storearr,$udom,$uhome,$encrypt)=@_; + my ($namespace,$storearr,$udom,$uhome)=@_; return if ($udom eq 'public'); my $items=''; foreach my $item (@$storearr) { @@ -2006,15 +2138,10 @@ sub get_dom { } if ($udom && $uhome && ($uhome ne 'no_host')) { my $rep; - if (grep { $_ eq $uhome } ¤t_machine_ids()) { - # domain information is hosted on this machine - $rep = &LONCAPA::Lond::get_dom("getdom:$udom:$namespace:$items"); + if ($namespace =~ /^enc/) { + $rep=&reply("encrypt:egetdom:$udom:$namespace:$items",$uhome); } else { - if ($encrypt) { - $rep=&reply("encrypt:egetdom:$udom:$namespace:$items",$uhome); - } else { - $rep=&reply("getdom:$udom:$namespace:$items",$uhome); - } + $rep=&reply("getdom:$udom:$namespace:$items",$uhome); } my %returnhash; if ($rep eq '' || $rep =~ /^error: 2 /) { @@ -2038,7 +2165,7 @@ sub get_dom { # -------------------------------------------- put items in domain db files sub put_dom { - my ($namespace,$storehash,$udom,$uhome,$encrypt)=@_; + my ($namespace,$storehash,$udom,$uhome)=@_; if (!$udom) { $udom=$env{'user.domain'}; if (defined(&domain($udom,'primary'))) { @@ -2059,7 +2186,7 @@ sub put_dom { $items.=&escape($item).'='.&freeze_escape($$storehash{$item}).'&'; } $items=~s/\&$//; - if ($encrypt) { + if ($namespace =~ /^enc/) { return &reply("encrypt:putdom:$udom:$namespace:$items",$uhome); } else { return &reply("putdom:$udom:$namespace:$items",$uhome); @@ -2097,57 +2224,6 @@ sub del_dom { } } -sub store_dom { - my ($storehash,$id,$namespace,$dom,$home,$encrypt) = @_; - $$storehash{'ip'}=&get_requestor_ip(); - $$storehash{'host'}=$perlvar{'lonHostID'}; - my $namevalue=''; - foreach my $key (keys(%{$storehash})) { - $namevalue.=&escape($key).'='.&freeze_escape($$storehash{$key}).'&'; - } - $namevalue=~s/\&$//; - if (grep { $_ eq $home } current_machine_ids()) { - return LONCAPA::Lond::store_dom("storedom:$dom:$namespace:$id:$namevalue"); - } else { - if ($namespace eq 'private') { - return 'refused'; - } elsif ($encrypt) { - return reply("encrypt:storedom:$dom:$namespace:$id:$namevalue",$home); - } else { - return reply("storedom:$dom:$namespace:$id:$namevalue",$home); - } - } -} - -sub restore_dom { - my ($id,$namespace,$dom,$home,$encrypt) = @_; - my $answer; - if (grep { $_ eq $home } current_machine_ids()) { - $answer = LONCAPA::Lond::restore_dom("restoredom:$dom:$namespace:$id"); - } elsif ($namespace ne 'private') { - if ($encrypt) { - $answer=&reply("encrypt:restoredom:$dom:$namespace:$id",$home); - } else { - $answer=&reply("restoredom:$dom:$namespace:$id",$home); - } - } - my %returnhash=(); - unless (($answer eq '') || ($answer eq 'con_lost') || ($answer eq 'refused') || - ($answer eq 'unknown_cmd') || ($answer eq 'rejected')) { - foreach my $line (split(/\&/,$answer)) { - my ($name,$value)=split(/\=/,$line); - $returnhash{&unescape($name)}=&thaw_unescape($value); - } - my $version; - for ($version=1;$version<=$returnhash{'version'};$version++) { - foreach my $item (split(/\:/,$returnhash{$version.':keys'})) { - $returnhash{$item}=$returnhash{$version.':'.$item}; - } - } - } - return %returnhash; -} - # ----------------------------------construct domainconfig user for a domain sub get_domainconfiguser { my ($udom) = @_; @@ -2190,7 +2266,7 @@ sub retrieve_inst_usertypes { sub is_domainimage { my ($url) = @_; - if ($url=~m-^/+res/+($match_domain)/+\1\-domainconfig/+(img|logo|domlogo|login)/+[^/]-) { + if ($url=~m-^/+res/+($match_domain)/+\1\-domainconfig/+(img|logo|domlogo)/+[^/]-) { if (&domain($1) ne '') { return '1'; } @@ -2208,10 +2284,9 @@ sub inst_directory_query { unless ($homeserver eq $perlvar{'lonHostID'}) { if ($srch->{'srchby'} eq 'email') { my $lcrev = &get_server_loncaparev($udom,$homeserver); - my ($major,$minor,$subver) = ($lcrev =~ /^\'?(\d+)\.(\d+)\.(\d+)[\w.\-]+\'?$/); + my ($major,$minor) = ($lcrev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/); if (($major eq '' && $minor eq '') || ($major < 2) || - (($major == 2) && ($minor < 11)) || - (($major == 2) && ($minor == 11) && ($subver < 3))) { + (($major == 2) && ($minor < 12))) { return; } } @@ -2260,10 +2335,9 @@ sub usersearch { unless ($tryserver eq $perlvar{'lonHostID'}) { if ($srch->{'srchby'} eq 'email') { my $lcrev = &get_server_loncaparev($dom,$tryserver); - my ($major,$minor,$subver) = ($lcrev =~ /^\'?(\d+)\.(\d+)\.(\d+)[\w.\-]+\'?$/); + my ($major,$minor) = ($lcrev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/); next if (($major eq '' && $minor eq '') || ($major < 2) || - (($major == 2) && ($minor < 11)) || - (($major == 2) && ($minor == 11) && ($subver < 3))); + (($major == 2) && ($minor < 12))); } } my $host=&hostname($tryserver); @@ -2355,7 +2429,7 @@ sub get_multiple_instusers { my ($udom,$users,$caller) = @_; my ($outcome,$results); if (ref($users) eq 'HASH') { - my $count = keys(%{$users}); + my $count = keys(%{$users}); my $requested = &freeze_escape($users); my $homeserver = &domain($udom,'primary'); if ($homeserver ne '') { @@ -2399,7 +2473,7 @@ sub get_multiple_instusers { } else { ($outcome,my $userdata) = split(/=/,$response,2); if ($outcome eq 'ok') { - $results = &thaw_unescape($userdata); + $results = &thaw_unescape($userdata); } } } @@ -2426,10 +2500,6 @@ sub inst_rulecheck { $response=&unescape(&reply('instidrulecheck:'.&escape($udom). ':'.&escape($id).':'.$rulestr, $homeserver)); - } elsif ($item eq 'unamemap') { - $response=&unescape(&reply('instunamemapcheck:'. - &escape($udom).':'.&escape($uname). - ':'.$rulestr,$homeserver)); } elsif ($item eq 'selfcreate') { $response=&unescape(&reply('instselfcreatecheck:'. &escape($udom).':'.&escape($uname). @@ -2463,9 +2533,6 @@ sub inst_userrules { } elsif ($check eq 'email') { $response=&reply('instemailrules:'.&escape($udom), $homeserver); - } elsif ($check eq 'unamemap') { - $response=&reply('unamemaprules:'.&escape($udom), - $homeserver); } else { $response=&reply('instuserrules:'.&escape($udom), $homeserver); @@ -2511,11 +2578,9 @@ sub get_domain_defaults { 'requestcourses','inststatus', 'coursedefaults','usersessions', 'requestauthor','selfenrollment', - 'coursecategories','autoenroll', - 'helpsettings','wafproxy','ltisec', - 'toolsec','domexttool','exttool'], - $domain); - my @coursetypes = ('official','unofficial','community','textbook'); + 'coursecategories','ssl','autoenroll', + 'trust','helpsettings'],$domain); + my @coursetypes = ('official','unofficial','community','textbook','placement'); if (ref($domconfig{'defaults'}) eq 'HASH') { $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'}; $domdefaults{'auth_def'} = $domconfig{'defaults'}{'auth_def'}; @@ -2523,12 +2588,9 @@ sub get_domain_defaults { $domdefaults{'timezone_def'} = $domconfig{'defaults'}{'timezone_def'}; $domdefaults{'datelocale_def'} = $domconfig{'defaults'}{'datelocale_def'}; $domdefaults{'portal_def'} = $domconfig{'defaults'}{'portal_def'}; - $domdefaults{'portal_def_email'} = $domconfig{'defaults'}{'portal_def_email'}; - $domdefaults{'portal_def_web'} = $domconfig{'defaults'}{'portal_def_web'}; $domdefaults{'intauth_cost'} = $domconfig{'defaults'}{'intauth_cost'}; $domdefaults{'intauth_switch'} = $domconfig{'defaults'}{'intauth_switch'}; $domdefaults{'intauth_check'} = $domconfig{'defaults'}{'intauth_check'}; - $domdefaults{'unamemap_rule'} = $domconfig{'defaults'}{'unamemap_rule'}; } else { $domdefaults{'lang_def'} = &domain($domain,'lang_def'); $domdefaults{'auth_def'} = &domain($domain,'auth_def'); @@ -2551,7 +2613,7 @@ sub get_domain_defaults { } } if (ref($domconfig{'requestcourses'}) eq 'HASH') { - foreach my $item ('official','unofficial','community','textbook') { + foreach my $item ('official','unofficial','community','textbook','placement') { $domdefaults{$item} = $domconfig{'requestcourses'}{$item}; } } @@ -2564,8 +2626,8 @@ sub get_domain_defaults { } } if (ref($domconfig{'coursedefaults'}) eq 'HASH') { + $domdefaults{'canuse_pdfforms'} = $domconfig{'coursedefaults'}{'canuse_pdfforms'}; $domdefaults{'usejsme'} = $domconfig{'coursedefaults'}{'usejsme'}; - $domdefaults{'inline_chem'} = $domconfig{'coursedefaults'}{'inline_chem'}; $domdefaults{'uselcmath'} = $domconfig{'coursedefaults'}{'uselcmath'}; if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') { $domdefaults{'postsubmit'} = $domconfig{'coursedefaults'}{'postsubmit'}{'client'}; @@ -2579,25 +2641,12 @@ sub get_domain_defaults { if (ref($domconfig{'coursedefaults'}{'uploadquota'}) eq 'HASH') { $domdefaults{$type.'quota'} = $domconfig{'coursedefaults'}{'uploadquota'}{$type}; } - if (ref($domconfig{'coursedefaults'}{'coursequota'}) eq 'HASH') { - $domdefaults{$type.'coursequota'} = $domconfig{'coursedefaults'}{'coursequota'}{$type}; - } if ($domdefaults{'postsubmit'} eq 'on') { if (ref($domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') { - $domdefaults{$type.'postsubtimeout'} = - $domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}{$type}; + $domdefaults{$type.'postsubtimeout'} = + $domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}{$type}; } } - if (ref($domconfig{'coursedefaults'}{'domexttool'}) eq 'HASH') { - $domdefaults{$type.'domexttool'} = $domconfig{'coursedefaults'}{'domexttool'}{$type}; - } else { - $domdefaults{$type.'domexttool'} = 1; - } - if (ref($domconfig{'coursedefaults'}{'exttool'}) eq 'HASH') { - $domdefaults{$type.'exttool'} = $domconfig{'coursedefaults'}{'exttool'}{$type}; - } else { - $domdefaults{$type.'exttool'} = 0; - } } if (ref($domconfig{'coursedefaults'}{'canclone'}) eq 'HASH') { if (ref($domconfig{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') { @@ -2611,10 +2660,7 @@ sub get_domain_defaults { } if ($domconfig{'coursedefaults'}{'texengine'}) { $domdefaults{'texengine'} = $domconfig{'coursedefaults'}{'texengine'}; - } - if (exists($domconfig{'coursedefaults'}{'ltiauth'})) { - $domdefaults{'crsltiauth'} = $domconfig{'coursedefaults'}{'ltiauth'}; - } + } } if (ref($domconfig{'usersessions'}) eq 'HASH') { if (ref($domconfig{'usersessions'}{'remote'}) eq 'HASH') { @@ -2626,9 +2672,6 @@ sub get_domain_defaults { if (ref($domconfig{'usersessions'}{'offloadnow'}) eq 'HASH') { $domdefaults{'offloadnow'} = $domconfig{'usersessions'}{'offloadnow'}; } - if (ref($domconfig{'usersessions'}{'offloadoth'}) eq 'HASH') { - $domdefaults{'offloadoth'} = $domconfig{'usersessions'}{'offloadoth'}; - } } if (ref($domconfig{'selfenrollment'}) eq 'HASH') { if (ref($domconfig{'selfenrollment'}{'admin'}) eq 'HASH') { @@ -2668,9 +2711,27 @@ sub get_domain_defaults { $domdefaults{'catunauth'} = $domconfig{'coursecategories'}{'unauth'}; } } + if (ref($domconfig{'ssl'}) eq 'HASH') { + if (ref($domconfig{'ssl'}{'replication'}) eq 'HASH') { + $domdefaults{'replication'} = $domconfig{'ssl'}{'replication'}; + } + if (ref($domconfig{'ssl'}{'connto'}) eq 'HASH') { + $domdefaults{'connect'} = $domconfig{'ssl'}{'connto'}; + } + if (ref($domconfig{'ssl'}{'connfrom'}) eq 'HASH') { + $domdefaults{'connect'} = $domconfig{'ssl'}{'connfrom'}; + } + } + if (ref($domconfig{'trust'}) eq 'HASH') { + my @prefixes = qw(content shared enroll othcoau coaurem domroles catalog reqcrs msg); + foreach my $prefix (@prefixes) { + if (ref($domconfig{'trust'}{$prefix}) eq 'HASH') { + $domdefaults{'trust'.$prefix} = $domconfig{'trust'}{$prefix}; + } + } + } if (ref($domconfig{'autoenroll'}) eq 'HASH') { $domdefaults{'autofailsafe'} = $domconfig{'autoenroll'}{'autofailsafe'}; - $domdefaults{'failsafe'} = $domconfig{'autoenroll'}{'failsafe'}; } if (ref($domconfig{'helpsettings'}) eq 'HASH') { $domdefaults{'submitbugs'} = $domconfig{'helpsettings'}{'submitbugs'}; @@ -2678,36 +2739,6 @@ sub get_domain_defaults { $domdefaults{'adhocroles'} = $domconfig{'helpsettings'}{'adhoc'}; } } - if (ref($domconfig{'wafproxy'}) eq 'HASH') { - foreach my $item ('ipheader','trusted','vpnint','vpnext','sslopt') { - if ($domconfig{'wafproxy'}{$item}) { - $domdefaults{'waf_'.$item} = $domconfig{'wafproxy'}{$item}; - } - } - } - if (ref($domconfig{'ltisec'}) eq 'HASH') { - if (ref($domconfig{'ltisec'}{'encrypt'}) eq 'HASH') { - $domdefaults{'linkprotenc_crs'} = $domconfig{'ltisec'}{'encrypt'}{'crs'}; - $domdefaults{'linkprotenc_dom'} = $domconfig{'ltisec'}{'encrypt'}{'dom'}; - $domdefaults{'ltienc_consumers'} = $domconfig{'ltisec'}{'encrypt'}{'consumers'}; - } - if (ref($domconfig{'ltisec'}{'private'}) eq 'HASH') { - if (ref($domconfig{'ltisec'}{'private'}{'keys'}) eq 'ARRAY') { - $domdefaults{'ltiprivhosts'} = $domconfig{'ltisec'}{'private'}{'keys'}; - } - } - } - if (ref($domconfig{'toolsec'}) eq 'HASH') { - if (ref($domconfig{'toolsec'}{'encrypt'}) eq 'HASH') { - $domdefaults{'toolenc_crs'} = $domconfig{'toolsec'}{'encrypt'}{'crs'}; - $domdefaults{'toolenc_dom'} = $domconfig{'toolsec'}{'encrypt'}{'dom'}; - } - if (ref($domconfig{'toolsec'}{'private'}) eq 'HASH') { - if (ref($domconfig{'toolsec'}{'private'}{'keys'}) eq 'ARRAY') { - $domdefaults{'toolprivhosts'} = $domconfig{'toolsec'}{'private'}{'keys'}; - } - } - } &do_cache_new('domdefaults',$domain,\%domdefaults,$cachetime); return %domdefaults; } @@ -2744,7 +2775,6 @@ sub get_dom_instcats { if (&auto_instcode_format($caller,$dom,\%coursecodes,\%codes, \@codetitles,\%cat_titles,\%cat_order) eq 'ok') { $instcats = { - totcodes => $totcodes, codes => \%codes, codetitles => \@codetitles, cat_titles => \%cat_titles, @@ -2772,6 +2802,22 @@ sub retrieve_instcodes { return $totcodes; } +sub course_portal_url { + my ($cnum,$cdom) = @_; + my $chome = &homeserver($cnum,$cdom); + my $hostname = &hostname($chome); + my $protocol = $protocol{$chome}; + $protocol = 'http' if ($protocol ne 'https'); + my %domdefaults = &get_domain_defaults($cdom); + my $firsturl; + if ($domdefaults{'portal_def'}) { + $firsturl = $domdefaults{'portal_def'}; + } else { + $firsturl = $protocol.'://'.$hostname; + } + return $firsturl; +} + # --------------------------------------------- Get domain config for passwords sub get_passwdconf { @@ -2795,44 +2841,6 @@ sub get_passwdconf { return %passwdconf; } -sub course_portal_url { - my ($cnum,$cdom,$r) = @_; - my $chome = &homeserver($cnum,$cdom); - my $hostname = &hostname($chome); - my $protocol = $protocol{$chome}; - $protocol = 'http' if ($protocol ne 'https'); - my %domdefaults = &get_domain_defaults($cdom); - my $firsturl; - if ($domdefaults{'portal_def'}) { - $firsturl = $domdefaults{'portal_def'}; - } else { - my $alias = &Apache::lonnet::use_proxy_alias($r,$chome); - $hostname = $alias if ($alias ne ''); - $firsturl = $protocol.'://'.$hostname; - } - return $firsturl; -} - -sub url_prefix { - my ($r,$dom,$home,$context) = @_; - my $prefix; - my %domdefs = &get_domain_defaults($dom); - if ($domdefs{'portal_def'} && $domdefs{'portal_def_'.$context}) { - if ($domdefs{'portal_def'} =~ m{^(https?://[^/]+)}) { - $prefix = $1; - } - } - if ($prefix eq '') { - my $hostname = &hostname($home); - my $protocol = $protocol{$home}; - $protocol = 'http' if ($protocol{$home} ne 'https'); - my $alias = &use_proxy_alias($r,$home); - $hostname = $alias if ($alias ne ''); - $prefix = $protocol.'://'.$hostname; - } - return $prefix; -} - # --------------------------------------------------- Assign a key to a student sub assign_access_key { @@ -3078,9 +3086,7 @@ sub devalidate_cache_new { sub is_cached_new { my ($name,$id,$debug) = @_; - my $remembered_id=$name.':'.$id; # this is to avoid make_key (which is slow) for - # keys in %remembered hash, which persists for - # duration of request (no restriction on key length). + my $remembered_id=$name.':'.$id; # this is to avoid make_key (which is slow) whenever possible if (exists($remembered{$remembered_id})) { if ($debug) { &Apache::lonnet::logthis("Early return $remembered_id of $remembered{$remembered_id} "); } $accessed{$remembered_id}=[&gettimeofday()]; @@ -3342,9 +3348,13 @@ sub repcopy { mkdir($path,0777); } } - my $ua=new LWP::UserAgent; my $request=new HTTP::Request('GET',"$remoteurl"); - my $response=$ua->request($request,$transname); + my $response; + if ($remoteurl =~ m{/raw/}) { + $response=&LONCAPA::LWPReq::makerequest($home,$request,$transname,\%perlvar,'',0,1); + } else { + $response=&LONCAPA::LWPReq::makerequest($home,$request,$transname,\%perlvar,'',1); + } if ($response->is_error()) { unlink($transname); my $message=$response->status_line; @@ -3354,7 +3364,12 @@ sub repcopy { } else { if ($remoteurl!~/\.meta$/) { my $mrequest=new HTTP::Request('GET',$remoteurl.'.meta'); - my $mresponse=$ua->request($mrequest,$filename.'.meta'); + my $mresponse; + if ($remoteurl =~ m{/raw/}) { + $mresponse = &LONCAPA::LWPReq::makerequest($home,$mrequest,$filename.'.meta',\%perlvar,'',0,1); + } else { + $mresponse = &LONCAPA::LWPReq::makerequest($home,$mrequest,$filename.'.meta',\%perlvar,'',1); + } if ($mresponse->is_error()) { unlink($filename.'.meta'); &logthis( @@ -3384,7 +3399,12 @@ sub unsubscribe { } elsif (grep { $_ eq $home } ¤t_machine_ids()) { $answer = 'home'; } else { - $answer = reply("unsub:$fname",$home); + my $defdom = $perlvar{'lonDefDomain'}; + if (&will_trust('content',$defdom,$udom)) { + $answer = reply("unsub:$fname",$home); + } else { + $answer = 'untrusted'; + } } return $answer; } @@ -3417,29 +3437,11 @@ sub ssi_body { # --------------------------------------------------------- Server Side Include sub absolute_url { - my ($host_name,$unalias,$keep_proto) = @_; + my ($host_name) = @_; my $protocol = ($ENV{'SERVER_PORT'} == 443?'https://':'http://'); if ($host_name eq '') { $host_name = $ENV{'SERVER_NAME'}; } - if ($unalias) { - my $alias = &get_proxy_alias(); - if ($alias eq $host_name) { - my $lonhost = $perlvar{'lonHostID'}; - my $hostname = &hostname($lonhost); - my $lcproto; - if (($keep_proto) || ($hostname eq '')) { - $lcproto = $protocol; - } else { - $lcproto = $protocol{$lonhost}; - $lcproto = 'http' if ($lcproto ne 'https'); - $lcproto .= '://'; - } - unless ($hostname eq '') { - return $lcproto.$hostname; - } - } - } return $protocol.$host_name; } @@ -3456,48 +3458,36 @@ sub absolute_url { sub ssi { my ($fn,%form)=@_; - my ($host,$request,$response); - $host = &absolute_url('',1); + my $request; $form{'no_update_last_known'}=1; &Apache::lonenc::check_encrypt(\$fn); if (%form) { - $request=new HTTP::Request('POST',$host.$fn); - $request->content(join('&',map { + $request=new HTTP::Request('POST',&absolute_url().$fn); + $request->content(join('&',map { my $name = escape($_); - "$name=" . ( ref($form{$_}) eq 'ARRAY' - ? join("&$name=", map {escape($_) } @{$form{$_}}) - : &escape($form{$_}) ); + "$name=" . ( ref($form{$_}) eq 'ARRAY' + ? join("&$name=", map {escape($_) } @{$form{$_}}) + : &escape($form{$_}) ); } keys(%form))); } else { - $request=new HTTP::Request('GET',$host.$fn); + $request=new HTTP::Request('GET',&absolute_url().$fn); } $request->header(Cookie => $ENV{'HTTP_COOKIE'}); - + my $lonhost = $perlvar{'lonHostID'}; + 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'}:'')))) { - if (LWP::UserAgent->VERSION >= 5.834) { - my $ua=new LWP::UserAgent; - $ua->local_address('127.0.0.1'); - $response = $ua->request($request); - } else { - { - require LWP::Protocol::http; - local @LWP::Protocol::http::EXTRA_SOCK_OPTS = (LocalAddr => '127.0.0.1'); - my $ua=new LWP::UserAgent; - $response = $ua->request($request); - @LWP::Protocol::http::EXTRA_SOCK_OPTS = (); - } - } - } else { - my $ua=new LWP::UserAgent; - $response = $ua->request($request); + $islocal = 1; } + my $response= &LONCAPA::LWPReq::makerequest($lonhost,$request,'',\%perlvar, + '','','',$islocal); + if (wantarray) { return ($response->content, $response); } else { @@ -3507,9 +3497,8 @@ sub ssi { sub externalssi { my ($url)=@_; - my $ua=new LWP::UserAgent; my $request=new HTTP::Request('GET',$url); - my $response=$ua->request($request); + my $response = &LONCAPA::LWPReq::makerequest('',$request,'',\%perlvar); if (wantarray) { return ($response->content, $response); } else { @@ -3517,8 +3506,9 @@ sub externalssi { } } -# If the local copy of a replicated resource is outdated, trigger a -# connection from the homeserver to flush the delayed queue. If no update + +# If the local copy of a replicated resource is outdated, trigger a +# connection from the homeserver to flush the delayed queue. If no update # happens, remove local copies of outdated resource (and corresponding # metadata file). @@ -3538,11 +3528,9 @@ sub remove_stale_resfile { if ($hostname) { my $protocol = $protocol{$homeserver}; $protocol = 'http' if ($protocol ne 'https'); - my $uri = $protocol.'://'.$hostname.'/raw/'.&declutter($url); - my $ua=new LWP::UserAgent; - $ua->timeout(5); - my $request=new HTTP::Request('HEAD',$uri); - my $response=$ua->request($request); + my $uri = &declutter($url); + my $request=new HTTP::Request('HEAD',$protocol.'://'.$hostname.'/raw/'.$uri); + my $response = &LONCAPA::LWPReq::makerequest($homeserver,$request,'',\%perlvar,5,0,1); if ($response->is_success()) { my $remmodtime = &HTTP::Date::str2time( $response->header('Last-modified') ); my $locmodtime = (stat($fname))[9]; @@ -3605,7 +3593,7 @@ sub allowuploaded { # # Determine if the current user should be able to edit a particular resource, # when viewing in course context. -# (a) When viewing resource used to determine if "Edit" item is included in +# (a) When viewing resource used to determine if "Edit" item is included in # Functions. # (b) When displaying folder contents in course editor, used to determine if # "Edit" link will be displayed alongside resource. @@ -3613,12 +3601,12 @@ sub allowuploaded { # input: six args -- filename (decluttered), course number, course domain, # url, symb (if registered) and group (if this is a group # item -- e.g., bulletin board, group page etc.). -# output: array of five scalars -- +# output: array of five scalars -- # $cfile -- url for file editing if editable on current server # $home -- homeserver of resource (i.e., for author if published, # or course if uploaded.). # $switchserver -- 1 if server switch will be needed. -# $forceedit -- 1 if icon/link should be to go to edit mode +# $forceedit -- 1 if icon/link should be to go to edit mode # $forceview -- 1 if icon/link should be to go to view mode # @@ -3707,7 +3695,7 @@ sub can_edit_resource { $forceedit = 1; } $cfile = $resurl; - } elsif (($resurl ne '') && (&is_on_map($resurl))) { + } elsif (($resurl ne '') && (&is_on_map($resurl))) { if ($resurl =~ m{^/adm/$match_domain/$match_username/\d+/smppg|bulletinboard$}) { $incourse = 1; if ($env{'form.forceedit'}) { @@ -3758,7 +3746,7 @@ sub can_edit_resource { } } elsif ($resurl eq '/res/lib/templates/simpleproblem.problem/smpedit') { my $template = '/res/lib/templates/simpleproblem.problem'; - if (&is_on_map($template)) { + if (&is_on_map($template)) { $incourse = 1; $forceview = 1; $cfile = $template; @@ -3818,7 +3806,7 @@ sub can_edit_resource { $cfile=$file; } } - if (($cfile ne '') && (!$incourse || $uploaded) && + if (($cfile ne '') && (!$incourse || $uploaded) && (($home ne '') && ($home ne 'no_host'))) { my @ids=¤t_machine_ids(); unless (grep(/^\Q$home\E$/,@ids)) { @@ -3845,9 +3833,9 @@ sub in_course { if ($hideprivileged) { my $skipuser; my %coursehash = &coursedescription($cdom.'_'.$cnum); - my @possdoms = ($cdom); - if ($coursehash{'checkforpriv'}) { - push(@possdoms,split(/,/,$coursehash{'checkforpriv'})); + my @possdoms = ($cdom); + if ($coursehash{'checkforpriv'}) { + push(@possdoms,split(/,/,$coursehash{'checkforpriv'})); } if (&privileged($uname,$udom,\@possdoms)) { $skipuser = 1; @@ -4041,10 +4029,6 @@ sub clean_filename { # Replace all .\d. sequences with _\d. so they no longer look like version # numbers $fname=~s/\.(\d+)(?=\.)/_$1/g; -# Replace three or more adjacent underscores with one for consistency -# with loncfile::filename_check() so complete url can be extracted by -# lonnet::decode_symb() - $fname=~s/_{3,}/_/g; return $fname; } @@ -4090,7 +4074,7 @@ sub resizeImage { # input: $formname - the contents of the file are in $env{"form.$formname"} # the desired filename is in $env{"form.$formname.filename"} # $context - possible values: coursedoc, existingfile, overwrite, -# canceloverwrite, scantron, toollogo or ''. +# canceloverwrite, scantron or ''. # if 'coursedoc': upload to the current course # if 'existingfile': write file to tmp/overwrites directory # if 'canceloverwrite': delete file written to tmp/overwrites directory @@ -4098,12 +4082,12 @@ sub resizeImage { # $subdir - directory in userfile to store the file into # $parser - instruction to parse file for objects ($parser = parse) or # if context is 'scantron', $parser is hashref of csv column mapping -# (e.g.,{ PaperID => 0, LastName => 1, FirstName => 2, ID => 3, +# (e.g.,{ PaperID => 0, LastName => 1, FirstName => 2, ID => 3, # Section => 4, CODE => 5, FirstQuestion => 9 }). # $allfiles - reference to hash for embedded objects # $codebase - reference to hash for codebase of java objects -# $destuname - username for permanent storage of uploaded file -# $destudom - domain for permanaent storage of uploaded file +# $desuname - username for permanent storage of uploaded file +# $dsetudom - domain for permanaent storage of uploaded file # $thumbwidth - width (pixels) of thumbnail to make for uploaded image # $thumbheight - height (pixels) of thumbnail to make for uploaded image # $resizewidth - width (pixels) to which to resize uploaded image @@ -4148,7 +4132,7 @@ sub userfileupload { } else { $docudom = $env{'user.domain'}; } - if ($destuname =~ /^$match_username$/) { + if ($destuname =~ /^$match_username$/) { $docuname = $destuname; } else { $docuname = $env{'user.name'}; @@ -4313,24 +4297,11 @@ sub finishuserfileupload { if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) { my $input = $filepath.'/'.$file; my $output = $filepath.'/'.'tn-'.$file; - my $makethumb; my $thumbsize = $thumbwidth.'x'.$thumbheight; - if ($context eq 'toollogo') { - my ($fullwidth,$fullheight) = &check_dimensions($input); - if ($fullwidth ne '' && $fullheight ne '') { - if ($fullwidth > $thumbwidth && $fullheight > $thumbheight) { - $makethumb = 1; - } - } - } else { - $makethumb = 1; - } - if ($makethumb) { - my @args = ('convert','-sample',$thumbsize,$input,$output); - system({$args[0]} @args); - if (-e $filepath.'/'.'tn-'.$file) { - $fetchthumb = 1; - } + my @args = ('convert','-sample',$thumbsize,$input,$output); + system({$args[0]} @args); + if (-e $filepath.'/'.'tn-'.$file) { + $fetchthumb = 1; } } @@ -4387,7 +4358,7 @@ sub extract_embedded_items { } if (lc($tagname) eq 'a') { unless (($attr->{'href'} =~ /^#/) || ($attr->{'href'} eq '')) { - &add_filetype($allfiles,$attr->{'href'},'href'); + &add_filetype($allfiles,$attr->{'href'},'href'); } } if (lc($tagname) eq 'script') { @@ -4562,37 +4533,13 @@ sub embedded_dependency { return; } -sub check_dimensions { - my ($inputfile) = @_; - my ($fullwidth,$fullheight); - if (($inputfile =~ m|^[/\w.\-]+$|) && (-e $inputfile)) { - my $mm = new File::MMagic; - my $mime_type = $mm->checktype_filename($inputfile); - if ($mime_type =~ m{^image/}) { - if (open(PIPE,"identify $inputfile 2>&1 |")) { - my $imageinfo = ; - if (!close(PIPE)) { - &Apache::lonnet::logthis("Failed to close PIPE opened to retrieve image information for $inputfile"); - } - chomp($imageinfo); - my ($fullsize) = - ($imageinfo =~ /^\Q$inputfile\E\s+\w+\s+(\d+x\d+)/); - if ($fullsize) { - ($fullwidth,$fullheight) = split(/x/,$fullsize); - } - } - } - } - return ($fullwidth,$fullheight); -} - sub bubblesheet_converter { my ($cdom,$fullpath,$config,$format) = @_; if ((&domain($cdom) ne '') && ($fullpath =~ m{^\Q$perlvar{'lonDocRoot'}/userfiles/$cdom/\E$match_courseid/scantron_orig}) && (-e $fullpath) && (ref($config) eq 'HASH') && ($format ne '')) { my (%csvcols,%csvoptions); - if (ref($config->{'fields'}) eq 'HASH') { + if (ref($config->{'fields'}) eq 'HASH') { %csvcols = %{$config->{'fields'}}; } if (ref($config->{'options'}) eq 'HASH') { @@ -4639,7 +4586,7 @@ sub bubblesheet_converter { next if (($num == 1) && ($csvoptions{'hdr'} == 1)); $line =~ s{[\r\n]+$}{}; my %found; - my @values = split(/,/,$line,-1); + my @values = split(/,/,$line); my ($qstart,$record); for (my $i=0; $i<@values; $i++) { if ((($qstart ne '') && ($i > $qstart)) || @@ -4822,7 +4769,6 @@ sub get_scantronformat_file { close($fh); } } - chomp(@lines); } return @lines; } @@ -4944,29 +4890,6 @@ sub flushcourselogs { if (! defined($dom) || $dom eq '' || ! defined($name) || $name eq '') { my $cid = $env{'request.course.id'}; -# -# FIXME 11/29/2021 -# Typo in rev. 1.458 (2003/12/09)?? -# These should likely by $env{'course.'.$cid.'.domain'} and $env{'course.'.$cid.'.num'} -# -# While these remain as $env{'request.'.$cid.'.domain'} and $env{'request.'.$cid.'.num'} -# $dom and $name will always be null, so the &inc() call will default to storing this data -# in a nohist_accesscount.db file for the user rather than the course. -# -# That said there is a lot of noise in the data being stored. -# So counts for prtspool/ and adm/ etc. are recorded. -# -# A review of which items ending '___count' are written to %accesshash should likely be -# made before deciding whether to set these to 'course.' instead of 'request.' -# -# Under the current scheme each user receives a nohist_accesscount.db file listing -# accesses for things which are not published resources, regardless of course, and -# there is not a nohist_accesscount.db file in a course, which might log accesses from -# anyone in the course for things which are not published resources. -# -# For an author, nohist_accesscount.db ends up having records for other items -# mixed up with the legitimate access counts for the author's published resources. -# $dom = $env{'request.'.$cid.'.domain'}; $name = $env{'request.'.$cid.'.num'}; } @@ -5015,19 +4938,19 @@ sub flushcourselogs { delete $domainrolehash{$entry}; } foreach my $dom (keys(%domrolebuffer)) { - my %servers; - if (defined(&domain($dom,'primary'))) { - my $primary=&domain($dom,'primary'); - my $hostname=&hostname($primary); - $servers{$primary} = $hostname; - } else { - %servers = &get_servers($dom,'library'); - } + my %servers; + if (defined(&domain($dom,'primary'))) { + my $primary=&domain($dom,'primary'); + my $hostname=&hostname($primary); + $servers{$primary} = $hostname; + } else { + %servers = &get_servers($dom,'library'); + } foreach my $tryserver (keys(%servers)) { if (&reply('domroleput:'.$dom.':'. - $domrolebuffer{$dom},$tryserver) eq 'ok') { - last; - } else { + $domrolebuffer{$dom},$tryserver) eq 'ok') { + last; + } else { &logthis('Put of domain roles failed for '.$dom.' and '.$tryserver); } } @@ -5076,11 +4999,7 @@ sub courseacclog { if ($formitem =~ /^HWFILE(?:SIZE|TOOBIG)/) { $what.=':'.$formitem.'='.$env{$key}; } elsif ($formitem !~ /^HWFILE(?:[^.]+)$/) { - if ($formitem eq 'proctorpassword') { - $what.=':'.$formitem.'=' . '*' x length($env{$key}); - } else { - $what.=':'.$formitem.'='.$env{$key}; - } + $what.=':'.$formitem.'='.$env{$key}; } } } @@ -5178,36 +5097,6 @@ sub courserolelog { $storehash{'group'} = $sec; } else { $storehash{'section'} = $sec; - my ($curruserdomstr,$newuserdomstr); - if (exists($env{'course.'.$cdom.'_'.$cnum.'.internal.userdomains'})) { - $curruserdomstr = $env{'course.'.$env{'request.course.id'}.'.internal.userdomains'}; - } else { - my %courseinfo = &coursedescription($cdom.'/'.$cnum); - $curruserdomstr = $courseinfo{'internal.userdomains'}; - } - if ($curruserdomstr ne '') { - my @udoms = split(/,/,$curruserdomstr); - unless (grep(/^\Q$domain\E/,@udoms)) { - push(@udoms,$domain); - $newuserdomstr = join(',',sort(@udoms)); - } - } else { - $newuserdomstr = $domain; - } - if ($newuserdomstr ne '') { - my $putresult = &put('environment',{ 'internal.userdomains' => $newuserdomstr }, - $cdom,$cnum); - if ($putresult eq 'ok') { - unless (($selfenroll) || ($context eq 'selfenroll')) { - if (($context eq 'createcourse') || ($context eq 'requestcourses') || - ($context eq 'automated') || ($context eq 'domain')) { - $env{'course.'.$cdom.'_'.$cnum.'.internal.userdomains'} = $newuserdomstr; - } elsif ($env{'request.course.id'} eq $cdom.'_'.$cnum) { - &appenv({'course.'.$cdom.'_'.$cnum.'.internal.userdomains' => $newuserdomstr}); - } - } - } - } } &write_log('course',$namespace,\%storehash,$delflag,$username, $domain,$cnum,$cdom); @@ -5389,7 +5278,7 @@ sub get_my_roles { } else { my $possdoms = [$domain]; if (ref($roledoms) eq 'ARRAY') { - push(@{$possdoms},@{$roledoms}); + push(@{$possdoms},@{$roledoms}); } if (&privileged($username,$domain,$possdoms,\@privroles)) { if (!$nothide{$username.':'.$domain}) { @@ -5686,16 +5575,16 @@ sub courseiddump { if (($domfilter eq '') || (&host_domain($tryserver) eq $domfilter)) { my $rep; - if (grep { $_ eq $tryserver } ¤t_machine_ids()) { - $rep = &LONCAPA::Lond::dump_course_id_handler( - join(":", (&host_domain($tryserver), $sincefilter, - &escape($descfilter), &escape($instcodefilter), + if (grep { $_ eq $tryserver } current_machine_ids()) { + $rep = LONCAPA::Lond::dump_course_id_handler( + join(":", (&host_domain($tryserver), $sincefilter, + &escape($descfilter), &escape($instcodefilter), &escape($ownerfilter), &escape($coursefilter), - &escape($typefilter), &escape($regexp_ok), - $as_hash, &escape($selfenrollonly), - &escape($catfilter), $showhidden, $caller, - &escape($cloner), &escape($cc_clone), $cloneonly, - &escape($createdbefore), &escape($createdafter), + &escape($typefilter), &escape($regexp_ok), + $as_hash, &escape($selfenrollonly), + &escape($catfilter), $showhidden, $caller, + &escape($cloner), &escape($cc_clone), $cloneonly, + &escape($createdbefore), &escape($createdafter), &escape($creationcontext),$domcloner,$hasuniquecode, $reqcrsdom,&escape($reqinstcode)))); } else { @@ -5711,7 +5600,7 @@ sub courseiddump { &escape($creationcontext).':'.$domcloner.':'.$hasuniquecode. ':'.$reqcrsdom.':'.&escape($reqinstcode),$tryserver); } - + my @pairs=split(/\&/,$rep); foreach my $item (@pairs) { my ($key,$value)=split(/\=/,$item,2); @@ -5938,93 +5827,6 @@ sub set_first_access { } } -sub checkout { - my ($symb,$tuname,$tudom,$tcrsid)=@_; - my $now=time; - my $lonhost=$perlvar{'lonHostID'}; - my $ip = &get_requestor_ip(); - my $infostr=&escape( - 'CHECKOUTTOKEN&'. - $tuname.'&'. - $tudom.'&'. - $tcrsid.'&'. - $symb.'&'. - $now.'&'.$ip); - my $token=&reply('tmpput:'.$infostr,$lonhost); - if ($token=~/^error\:/) { - &logthis("WARNING: ". - "Checkout tmpput failed ".$tudom.' - '.$tuname.' - '.$symb. - ""); - return ''; - } - - $token=~s/^(\d+)\_.*\_(\d+)$/$1\*$2\*$lonhost/; - $token=~tr/a-z/A-Z/; - - my %infohash=('resource.0.outtoken' => $token, - 'resource.0.checkouttime' => $now, - 'resource.0.outremote' => $ip); - - unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') { - return ''; - } else { - &logthis("WARNING: ". - "Checkout cstore failed ".$tudom.' - '.$tuname.' - '.$symb. - ""); - } - - if (&log($tudom,$tuname,&homeserver($tuname,$tudom), - &escape('Checkout '.$infostr.' - '. - $token)) ne 'ok') { - return ''; - } else { - &logthis("WARNING: ". - "Checkout log failed ".$tudom.' - '.$tuname.' - '.$symb. - ""); - } - return $token; -} - -# ------------------------------------------------------------ Check in an item - -sub checkin { - my $token=shift; - my $now=time; - my ($ta,$tb,$lonhost)=split(/\*/,$token); - $lonhost=~tr/A-Z/a-z/; - my $dtoken=$ta.'_'.&hostname($lonhost).'_'.$tb; - $dtoken=~s/\W/\_/g; - my $ip = &get_requestor_ip(); - my ($dummy,$tuname,$tudom,$tcrsid,$symb,$chtim,$rmaddr)= - split(/\&/,&unescape(&reply('tmpget:'.$dtoken,$lonhost))); - - unless (($tuname) && ($tudom)) { - &logthis('Check in '.$token.' ('.$dtoken.') failed'); - return ''; - } - - unless (&allowed('mgr',$tcrsid)) { - &logthis('Check in '.$token.' ('.$dtoken.') unauthorized: '. - $env{'user.name'}.' - '.$env{'user.domain'}); - return ''; - } - - my %infohash=('resource.0.intoken' => $token, - 'resource.0.checkintime' => $now, - 'resource.0.inremote' => $ip); - - unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') { - return ''; - } - - if (&log($tudom,$tuname,&homeserver($tuname,$tudom), - &escape('Checkin - '.$token)) ne 'ok') { - return ''; - } - - return ($symb,$tuname,$tudom,$tcrsid); -} - # --------------------------------------------- Set Expire Date for Spreadsheet sub expirespread { @@ -6279,7 +6081,7 @@ sub tmpreset { if (!$domain) { $domain=$env{'user.domain'}; } if (!$stuname) { $stuname=$env{'user.name'}; } if ($domain eq 'public' && $stuname eq 'public') { - $stuname=&get_requestor_ip(); + $stuname=$ENV{'REMOTE_ADDR'}; } my $path=LONCAPA::tempdir(); my %hash; @@ -6316,7 +6118,7 @@ sub tmpstore { if (!$domain) { $domain=$env{'user.domain'}; } if (!$stuname) { $stuname=$env{'user.name'}; } if ($domain eq 'public' && $stuname eq 'public') { - $stuname=&get_requestor_ip(); + $stuname=$ENV{'REMOTE_ADDR'}; } my $now=time; my %hash; @@ -6360,7 +6162,7 @@ sub tmprestore { if (!$domain) { $domain=$env{'user.domain'}; } if (!$stuname) { $stuname=$env{'user.name'}; } if ($domain eq 'public' && $stuname eq 'public') { - $stuname=&get_requestor_ip(); + $stuname=$ENV{'REMOTE_ADDR'}; } my %returnhash; $namespace=~s/\//\_/g; @@ -6416,7 +6218,7 @@ sub store { } if (!$home) { $home=$env{'user.home'}; } - $$storehash{'ip'}=&get_requestor_ip(); + $$storehash{'ip'}=$ENV{'REMOTE_ADDR'}; $$storehash{'host'}=$perlvar{'lonHostID'}; my $namevalue=''; @@ -6452,7 +6254,7 @@ sub cstore { } if (!$home) { $home=$env{'user.home'}; } - $$storehash{'ip'}=&get_requestor_ip(); + $$storehash{'ip'}=$ENV{'REMOTE_ADDR'}; $$storehash{'host'}=$perlvar{'lonHostID'}; my $namevalue=''; @@ -6618,7 +6420,7 @@ sub privileged { my $now = time; my $roles; if (ref($possroles) eq 'ARRAY') { - $roles = $possroles; + $roles = $possroles; } else { $roles = ['dc','su']; } @@ -6645,7 +6447,7 @@ sub privileged { for my $role (@rolesdump{grep { ! /^rolesdef_/ } keys(%rolesdump)}) { my ($trole, $tend, $tstart) = split(/_/, $role); if (grep(/^\Q$trole\E$/,@{$roles})) { - return 1 unless ($tend && $tend < $now) + return 1 unless ($tend && $tend < $now) or ($tstart && $tstart > $now); } } @@ -6683,7 +6485,7 @@ sub privileged_by_domain { my ($trole,$uname,$udom,$rest) = split(/:/,$item,4); my ($end,$start) = split(/:/,$dompersonnel{$server}{$item}); next if ($end && $end < $now); - $privileged{$dom}{$trole}{$uname.':'.$udom} = + $privileged{$dom}{$trole}{$uname.':'.$udom} = $dompersonnel{$server}{$item}; } } @@ -6870,31 +6672,31 @@ sub course_adhocrole_privs { $full{$priv} = $restrict; } foreach my $item (split(/,/,$overrides{"internal.adhocpriv.$rolename"})) { - next if ($item eq ''); - my ($rule,$rest) = split(/=/,$item); - next unless (($rule eq 'off') || ($rule eq 'on')); - foreach my $priv (split(/:/,$rest)) { - if ($priv ne '') { - if ($rule eq 'off') { - $possremove{$priv} = 1; - } else { - $possadd{$priv} = 1; - } - } - } - } - foreach my $priv (sort(keys(%full))) { - if (exists($currprivs{$priv})) { - unless (exists($possremove{$priv})) { - $storeprivs{$priv} = $currprivs{$priv}; - } - } elsif (exists($possadd{$priv})) { - $storeprivs{$priv} = $full{$priv}; - } - } - $coursepriv = ':'.join(':',map { $_.'&'.$storeprivs{$_}; } sort(keys(%storeprivs))); - } - return $coursepriv; + next if ($item eq ''); + my ($rule,$rest) = split(/=/,$item); + next unless (($rule eq 'off') || ($rule eq 'on')); + foreach my $priv (split(/:/,$rest)) { + if ($priv ne '') { + if ($rule eq 'off') { + $possremove{$priv} = 1; + } else { + $possadd{$priv} = 1; + } + } + } + } + foreach my $priv (sort(keys(%full))) { + if (exists($currprivs{$priv})) { + unless (exists($possremove{$priv})) { + $storeprivs{$priv} = $currprivs{$priv}; + } + } elsif (exists($possadd{$priv})) { + $storeprivs{$priv} = $full{$priv}; + } + } + $coursepriv = ':'.join(':',map { $_.'&'.$storeprivs{$_}; } sort(keys(%storeprivs))); + } + return $coursepriv; } sub group_roleprivs { @@ -7116,7 +6918,7 @@ sub check_adhoc_privs { my $cckey = 'user.role.'.$checkrole.'./'.$cdom.'/'.$cnum; if ($sec) { $cckey .= '/'.$sec; - } + } my $setprivs; if ($env{$cckey}) { my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus,$tpstart,$tpend); @@ -7162,7 +6964,7 @@ sub set_adhoc_privileges { ($caller eq 'tiny')) { &appenv( {'request.role' => $spec, 'request.role.domain' => $dcdom, - 'request.course.sec' => $sec, + 'request.course.sec' => $sec, } ); my $tadv=0; @@ -7222,19 +7024,20 @@ sub unserialize { return {} if $rep =~ /^error/; my %returnhash=(); - foreach my $item (split(/\&/,$rep)) { - my ($key, $value) = split(/=/, $item, 2); - $key = unescape($key) unless $escapedkeys; - next if $key =~ /^error: 2 /; - $returnhash{$key} = &thaw_unescape($value); - } + foreach my $item (split(/\&/,$rep)) { + my ($key, $value) = split(/=/, $item, 2); + $key = unescape($key) unless $escapedkeys; + next if $key =~ /^error: 2 /; + $returnhash{$key} = &thaw_unescape($value); + } + #return %returnhash; return \%returnhash; -} +} # see Lond::dump_with_regexp # if $escapedkeys hash keys won't get unescaped. sub dump { - my ($namespace,$udomain,$uname,$regexp,$range,$escapedkeys,$encrypt)=@_; + my ($namespace,$udomain,$uname,$regexp,$range,$escapedkeys)=@_; if (!$udomain) { $udomain=$env{'user.domain'}; } if (!$uname) { $uname=$env{'user.name'}; } my $uhome=&homeserver($uname,$udomain); @@ -7244,24 +7047,20 @@ sub dump { } else { $regexp='.'; } - if (grep { $_ eq $uhome } ¤t_machine_ids()) { + if (grep { $_ eq $uhome } current_machine_ids()) { # user is hosted on this machine - my $reply = LONCAPA::Lond::dump_with_regexp(join(':', ($udomain, + my $reply = LONCAPA::Lond::dump_with_regexp(join(":", ($udomain, $uname, $namespace, $regexp, $range)), $perlvar{'lonVersion'}); - return %{&unserialize($reply, $escapedkeys)}; - } - my $rep; - if ($encrypt) { - $rep=&reply("encrypt:edump:$udomain:$uname:$namespace:$regexp:$range",$uhome); - } else { - $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome); + return %{unserialize($reply, $escapedkeys)}; } + my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome); my @pairs=split(/\&/,$rep); my %returnhash=(); if (!($rep =~ /^error/ )) { foreach my $item (@pairs) { my ($key,$value)=split(/=/,$item,2); - $key = &unescape($key) unless ($escapedkeys); + $key = unescape($key) unless $escapedkeys; + #$key = &unescape($key); next if ($key =~ /^error: 2 /); $returnhash{$key}=&thaw_unescape($value); } @@ -7305,7 +7104,7 @@ sub currentdump { my $rep; if (grep { $_ eq $uhome } current_machine_ids()) { - $rep = LONCAPA::Lond::dump_profile_database(join(":", ($sdom, $sname, + $rep = LONCAPA::Lond::dump_profile_database(join(":", ($sdom, $sname, $courseid))); } else { $rep = reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome); @@ -7315,7 +7114,7 @@ sub currentdump { # my %returnhash=(); # - if ($rep eq "unknown_cmd") { + if ($rep eq 'unknown_cmd') { # an old lond will not know currentdump # Do a dump and make it look like a currentdump my @tmp = &dumpstore($courseid,$sdom,$sname,'.'); @@ -7401,7 +7200,7 @@ sub inc { # --------------------------------------------------------------- put interface sub put { - my ($namespace,$storehash,$udomain,$uname,$encrypt)=@_; + my ($namespace,$storehash,$udomain,$uname)=@_; if (!$udomain) { $udomain=$env{'user.domain'}; } if (!$uname) { $uname=$env{'user.name'}; } my $uhome=&homeserver($uname,$udomain); @@ -7410,11 +7209,7 @@ sub put { $items.=&escape($item).'='.&freeze_escape($$storehash{$item}).'&'; } $items=~s/\&$//; - if ($encrypt) { - return &reply("encrypt:put:$udomain:$uname:$namespace:$items",$uhome); - } else { - return &reply("put:$udomain:$uname:$namespace:$items",$uhome); - } + return &reply("put:$udomain:$uname:$namespace:$items",$uhome); } # ------------------------------------------------------------ newput interface @@ -7454,8 +7249,7 @@ sub putstore { foreach my $key (keys(%{$storehash})) { $namevalue.=&escape($key).'='.&freeze_escape($storehash->{$key}).'&'; } - my $ip = &get_requestor_ip(); - $namevalue .= 'ip='.&escape($ip). + $namevalue .= 'ip='.&escape($ENV{'REMOTE_ADDR'}). '&host='.&escape($perlvar{'lonHostID'}). '&version='.$esc_v. '&by='.&escape($env{'user.name'}.':'.$env{'user.domain'}); @@ -7571,13 +7365,13 @@ sub tmpdel { return &reply("tmpdel:$token",$server); } -# ------------------------------------------------------------ get_timebased_id +# ------------------------------------------------------------ get_timebased_id sub get_timebased_id { my ($prefix,$keyid,$namespace,$cdom,$cnum,$idtype,$who,$locktries, $maxtries) = @_; my ($newid,$error,$dellock); - unless (($prefix =~ /^\w+$/) && ($keyid =~ /^\w+$/) && ($namespace ne '')) { + unless (($prefix =~ /^\w+$/) && ($keyid =~ /^\w+$/) && ($namespace ne '')) { return ('','ok','invalid call to get suffix'); } @@ -7591,7 +7385,7 @@ sub get_timebased_id { if (!$maxtries) { $maxtries = 10; } - + if (($cdom eq '') || ($cnum eq '')) { if ($env{'request.course.id'}) { $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; @@ -7679,15 +7473,15 @@ sub portfolio_access { if ($result) { my %setters; if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') { - my ($startblock,$endblock,$triggerblock,$by_ip,$blockdom) = - &Apache::loncommon::blockcheck(\%setters,'port',$clientip,$unum,$udom); - if (($startblock && $endblock) || ($by_ip)) { + my ($startblock,$endblock) = + &Apache::loncommon::blockcheck(\%setters,'port',$unum,$udom); + if ($startblock && $endblock) { return 'B'; } } else { - my ($startblock,$endblock,$triggerblock,$by_ip,$blockdo) = - &Apache::loncommon::blockcheck(\%setters,'port',$clientip); - if (($startblock && $endblock) || ($by_ip)) { + my ($startblock,$endblock) = + &Apache::loncommon::blockcheck(\%setters,'port'); + if ($startblock && $endblock) { return 'B'; } } @@ -7746,7 +7540,7 @@ sub get_portfolio_access { if (ref($access_hash->{$ipkey}{'ip'}) eq 'ARRAY') { if (&Apache::loncommon::check_ip_acc(join(',',@{$access_hash->{$ipkey}{'ip'}}),$clientip)) { $allowed = 1; - last; + last; } } } @@ -7928,17 +7722,6 @@ sub is_portfolio_file { return; } -sub is_coursetool_logo { - my ($uri) = @_; - if ($env{'request.course.id'}) { - my $courseurl = &courseid_to_courseurl($env{'request.course.id'}); - if ($uri =~ m{^/*uploaded\Q$courseurl\E/toollogo/\d+/[^/]+$}) { - return 1; - } - } - return; -} - sub usertools_access { my ($uname,$udom,$tool,$action,$context,$userenvref,$domdefref,$is_advref)=@_; my ($access,%tools); @@ -7951,6 +7734,7 @@ sub usertools_access { unofficial => 1, community => 1, textbook => 1, + placement => 1, lti => 1, ); } elsif ($context eq 'requestauthor') { @@ -7963,7 +7747,6 @@ sub usertools_access { blog => 1, webdav => 1, portfolio => 1, - timezone => 1, ); } return if (!defined($tools{$tool})); @@ -7987,7 +7770,7 @@ sub usertools_access { my ($toolstatus,$inststatus,$envkey); if ($context eq 'requestauthor') { - $envkey = $context; + $envkey = $context; } else { $envkey = $context.'.'.$tool; } @@ -8253,14 +8036,14 @@ sub customaccess { # ------------------------------------------------- Check for a user privilege sub allowed { - my ($priv,$uri,$symb,$role,$clientip,$noblockcheck,$ignorecache,$nodeeplinkcheck,$nodeeplinkout)=@_; + my ($priv,$uri,$symb,$role,$clientip,$noblockcheck,$ignorecache)=@_; my $ver_orguri=$uri; $uri=&deversion($uri); my $orguri=$uri; $uri=&declutter($uri); if ($priv eq 'evb') { -# Evade communication block restrictions for specified role in a course or domain +# Evade communication block restrictions for specified role in a course if ($env{'user.priv.'.$role} =~/evb\&([^\:]*)/) { return $1; } else { @@ -8270,7 +8053,7 @@ sub allowed { if (defined($env{'allowed.'.$priv})) { return $env{'allowed.'.$priv}; } # Free bre access to adm and meta resources - if (((($uri=~/^adm\//) && ($uri !~ m{/(?:smppg|bulletinboard|viewclasslist|aboutme|ext\.tool)$})) + if (((($uri=~/^adm\//) && ($uri !~ m{/(?:smppg|bulletinboard|ext\.tool)$})) || (($uri=~/\.meta$/) && ($uri!~m|^uploaded/|) )) && ($priv eq 'bre')) { return 'F'; @@ -8281,9 +8064,9 @@ sub allowed { if (($space=~/^(uploaded|editupload)$/) && ($env{'user.name'} eq $name) && ($env{'user.domain'} eq $domain) && ('portfolio' eq $dir[0])) { my %setters; - my ($startblock,$endblock,$triggerblock,$by_ip,$blockdom) = - &Apache::loncommon::blockcheck(\%setters,'port',$clientip); - if (($startblock && $endblock) || ($by_ip)) { + my ($startblock,$endblock) = + &Apache::loncommon::blockcheck(\%setters,'port'); + if ($startblock && $endblock) { return 'B'; } else { return 'F'; @@ -8379,8 +8162,8 @@ sub allowed { my $adom = $1; foreach my $key (keys(%env)) { if ($key =~ m{^user\.role\.(ca|aa)/\Q$adom\E}) { - my ($start,$end) = split(/\./,$env{$key}); - if (($now >= $start) && (!$end || $end > $now)) { + my ($start,$end) = split('.',$env{$key}); + if (($now >= $start) && (!$end || $end < $now)) { $ownaccess = 1; last; } @@ -8392,8 +8175,8 @@ sub allowed { foreach my $role ('ca','aa') { if ($env{"user.role.$role./$adom/$aname"}) { my ($start,$end) = - split(/\./,$env{"user.role.$role./$adom/$aname"}); - if (($now >= $start) && (!$end || $end > $now)) { + split('.',$env{"user.role.$role./$adom/$aname"}); + if (($now >= $start) && (!$end || $end < $now)) { $ownaccess = 1; last; } @@ -8478,10 +8261,7 @@ sub allowed { if ($env{'user.priv.'.$env{'request.role'}.'./'} =~/\Q$priv\E\&([^\:]*)/) { my $value = $1; - my $deeplinkblock; - unless ($nodeeplinkcheck) { - $deeplinkblock = &deeplink_check($priv,$symb,$uri); - } + my $deeplinkblock = &deeplink_check($priv,$symb,$uri); if ($deeplinkblock) { $thisallowed='D'; } elsif ($noblockcheck) { @@ -8504,10 +8284,7 @@ sub allowed { $refuri=&declutter($refuri); my ($match) = &is_on_map($refuri); if ($match) { - my $deeplinkblock; - unless ($nodeeplinkcheck) { - $deeplinkblock = &deeplink_check($priv,$symb,$refuri); - } + my $deeplinkblock = &deeplink_check($priv,$symb,$refuri); if ($deeplinkblock) { $thisallowed='D'; } elsif ($noblockcheck) { @@ -8532,7 +8309,7 @@ sub allowed { && &is_portfolio_url($uri)) { $thisallowed = &portfolio_access($uri,$clientip); } - + # Full access at system, domain or course-wide level? Exit. if ($thisallowed=~/F/) { return 'F'; @@ -8560,12 +8337,6 @@ sub allowed { if ($env{'request.course.id'}) { - if ($priv eq 'bre') { - if (&is_coursetool_logo($uri)) { - return 'F'; - } - } - # If this is modifying password (internal auth) domains must match for user and user's role. if ($priv eq 'mip') { @@ -8589,13 +8360,7 @@ sub allowed { =~/\Q$priv\E\&([^\:]*)/) { my $value = $1; if ($priv eq 'bre') { - my $deeplinkblock; - unless ($nodeeplinkcheck) { - $deeplinkblock = &deeplink_check($priv,$symb,$uri); - } - if ($deeplinkblock) { - $thisallowed = 'D'; - } elsif ($noblockcheck) { + if ($noblockcheck) { $thisallowed.=$value; } else { my @blockers = &has_comm_blocking($priv,$symb,$uri,$ignorecache); @@ -8637,10 +8402,7 @@ sub allowed { =~/\Q$priv\E\&([^\:]*)/) { my $value = $1; if ($priv eq 'bre') { - my $deeplinkblock; - unless ($nodeeplinkcheck) { - $deeplinkblock = &deeplink_check($priv,$symb,$refuri); - } + my $deeplinkblock = &deeplink_check($priv,$symb,$refuri); if ($deeplinkblock) { $thisallowed = 'D'; } elsif ($noblockcheck) { @@ -8688,48 +8450,16 @@ sub allowed { # # Possibly locked functionality, check all courses -# In roles.tab, L (unless locked) available for bre, pch, plc, pac and sma. # Locks might take effect only after 10 minutes cache expiration for other -# courses, and 2 minutes for current course, in which user has st or ta role -# which is neither expired nor a future role (unless current course). +# courses, and 2 minutes for current course - my ($needlockcheck,$now,$crsonly); + my $envkey; if ($thisallowed=~/L/) { - $now = time; - if ($priv eq 'bre') { - if ($uri ne '') { - if ($orguri =~ m{^/+res/}) { - if ($uri =~ m{^lib/templates/}) { - if ($env{'request.course.id'}) { - $crsonly = 1; - $needlockcheck = 1; - } - } else { - $needlockcheck = 1; - } - } elsif ($env{'request.course.id'}) { - my ($crsdom,$crsnum) = split('_',$env{'request.course.id'}); - if (($uri =~ m{^(adm|uploaded|public)/$crsdom/$crsnum/}) || - ($uri =~ m{^adm/$match_domain/$match_username/\d+/(smppg|bulletinboard)$})) { - $crsonly = 1; - } - $needlockcheck = 1; - } - } - } elsif (($priv eq 'pch') || ($priv eq 'plc') || ($priv eq 'pac') || ($priv eq 'sma')) { - $needlockcheck = 1; - } - } - if ($needlockcheck) { - foreach my $envkey (keys(%env)) { + foreach $envkey (keys(%env)) { if ($envkey=~/^user\.role\.(st|ta)\.([^\.]*)/) { my $courseid=$2; my $roleid=$1.'.'.$2; $courseid=~s/^\///; - unless ($env{'request.role'} eq $roleid) { - my ($start,$end) = split(/\./,$env{$envkey}); - next unless (($now >= $start) && (!$end || $end > $now)); - } my $expiretime=600; if ($env{'request.role'} eq $roleid) { $expiretime=120; @@ -8752,7 +8482,7 @@ sub allowed { } if (($env{$prefix.'priv.'.$priv.'.lock.sections'}=~/\,\Q$csec\E\,/) || ($env{$prefix.'priv.'.$priv.'.lock.sections'} eq 'all')) { - if ($env{$prefix.'priv.'.$priv.'.lock.expire'}>time) { + if ($env{'priv.'.$priv.'.lock.expire'}>time) { &log($env{'user.domain'},$env{'user.name'}, $env{'user.home'}, 'Locked by priv: '.$priv.' for '.$uri.' due to '. @@ -8791,7 +8521,7 @@ sub allowed { my $unamedom=$env{'user.name'}.':'.$env{'user.domain'}; if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.roles.denied'} =~/\Q$rolecode\E/) { - if (($priv ne 'pch') && ($priv ne 'plc')) { + if (($priv ne 'pch') && ($priv ne 'plc') && ($priv ne 'pac')) { &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'. 'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode.' in '. $env{'request.course.id'}); @@ -8801,7 +8531,7 @@ sub allowed { if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.users.denied'} =~/\Q$unamedom\E/) { - if (($priv ne 'pch') && ($priv ne 'plc')) { + if (($priv ne 'pch') && ($priv ne 'plc') && ($priv ne 'pac')) { &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}. 'Denied by user: '.$priv.' for '.$uri.' as '.$unamedom.' in '. $env{'request.course.id'}); @@ -8823,17 +8553,6 @@ sub allowed { } } -# Restricted for deeplinked session? - - if ($env{'request.deeplink.login'}) { - if ($env{'acc.deeplinkout'} && !$nodeeplinkout) { - if (!$symb) { $symb=&symbread($uri,1); } - if (($symb) && ($env{'acc.deeplinkout'}=~/\&\Q$symb\E\&/)) { - return ''; - } - } - } - # Restricted by state or randomout? if ($thisallowed=~/X/) { @@ -8872,7 +8591,7 @@ sub constructaccess { my ($ownername,$ownerdomain,$ownerhome); ($ownerdomain,$ownername) = - ($url=~ m{^(?:\Q$perlvar{'lonDocRoot'}\E|)/priv/($match_domain)/($match_username)(?:/|$)}); + ($url=~ m{^(?:\Q$perlvar{'lonDocRoot'}\E|)(?:/daxepage|/daxeopen)?/priv/($match_domain)/($match_username)(?:/|$)}); # The URL does not really point to any authorspace, forget it unless (($ownername) && ($ownerdomain)) { return ''; } @@ -8893,6 +8612,15 @@ sub constructaccess { $ownerhome = &homeserver($ownername,$ownerdomain); return ($ownername,$ownerdomain,$ownerhome); } + if ($env{'request.course.id'}) { + if (($ownername eq $env{'course.'.$env{'request.course.id'}.'.num'}) && + ($ownerdomain eq $env{'course.'.$env{'request.course.id'}.'.domain'})) { + if (&allowed('mdc',$env{'request.course.id'})) { + $ownerhome = $env{'course.'.$env{'request.course.id'}.'.home'}; + return ($ownername,$ownerdomain,$ownerhome); + } + } + } } # We don't have any access right now. If we are not possibly going to do anything about this, @@ -8937,14 +8665,14 @@ sub constructaccess { my $cacheduser=''; # Course for which data are being temporarily cached. my $cachedcid=''; -# Cached blockers for this user (a hash of blocking items). +# Cached blockers for this user (a hash of blocking items). my %cachedblockers=(); # When the data were last cached. my $cachedlast=''; sub load_all_blockers { my ($uname,$udom)=@_; - if (($uname ne '') && ($udom ne '')) { + if (($uname ne '') && ($udom ne '')) { if (($cacheduser eq $uname.':'.$udom) && ($cachedcid eq $env{'request.course.id'}) && (abs($cachedlast-time)<5)) { @@ -8982,18 +8710,14 @@ sub get_commblock_resources { my ($blocks) = @_; my %blockers = (); return %blockers unless ($env{'request.course.id'}); - my $courseurl = &courseid_to_courseurl($env{'request.course.id'}); - if ($env{'request.course.sec'}) { - $courseurl .= '/'.$env{'request.course.sec'}; - } - return %blockers if ($env{'user.priv.'.$env{'request.role'}.'.'.$courseurl} =~/evb\&([^\:]*)/); + return %blockers if ($env{'user.priv.'.$env{'request.role'}} =~/evb\&([^\:]*)/); my %commblocks; if (ref($blocks) eq 'HASH') { %commblocks = %{$blocks}; } else { %commblocks = &get_comm_blocks(); } - return %blockers unless (keys(%commblocks) > 0); + return %blockers unless (keys(%commblocks) > 0); my $navmap = Apache::lonnavmaps::navmap->new(); return %blockers unless (ref($navmap)); my $now = time; @@ -9005,7 +8729,7 @@ sub get_commblock_resources { if (ref($commblocks{$block}{'blocks'}{'docs'}) eq 'HASH') { if (ref($commblocks{$block}{'blocks'}{'docs'}{'maps'}) eq 'HASH') { if (keys(%{$commblocks{$block}{'blocks'}{'docs'}{'maps'}})) { - $blockers{$block}{maps} = $commblocks{$block}{'blocks'}{'docs'}{'maps'}; + $blockers{$block}{maps} = $commblocks{$block}{'blocks'}{'docs'}{'maps'}; } } if (ref($commblocks{$block}{'blocks'}{'docs'}{'resources'}) eq 'HASH') { @@ -9018,9 +8742,10 @@ sub get_commblock_resources { } } elsif ($block =~ /^firstaccess____(.+)$/) { my $item = $1; + my @to_test; if (ref($commblocks{$block}{'blocks'}) eq 'HASH') { if (ref($commblocks{$block}{'blocks'}{'docs'}) eq 'HASH') { - my (@interval,$mapname); + my @interval; my $type = 'map'; if ($item eq 'course') { $type = 'course'; @@ -9029,16 +8754,41 @@ sub get_commblock_resources { if ($item =~ /___\d+___/) { $type = 'resource'; @interval=&EXT("resource.0.interval",$item); + if (ref($navmap)) { + my $res = $navmap->getBySymb($item); + push(@to_test,$res); + } } else { - $mapname = &deversion($item); - if (ref($navmap)) { - my $timelimit = $navmap->get_mapparam(undef,$mapname,'0.interval'); - @interval = ($timelimit,'map'); + my $mapsymb = &symbread($item,1); + if ($mapsymb) { + if (ref($navmap)) { + my $mapres = $navmap->getBySymb($mapsymb); + if (ref($mapres)) { + my $first = $mapres->map_start(); + my $finish = $mapres->map_finish(); + my $it = $navmap->getIterator($first,$finish,undef,0,0); + if (ref($it)) { + my $res; + while ($res = $it->next(undef,1)) { + next unless (ref($res)); + my $symb = $res->symb(); + next if (($symb eq $mapsymb) || ($symb eq '')); + @interval=&EXT("resource.0.interval",$symb); + if ($interval[1] eq 'map') { + if ($res->answerable()) { + push(@to_test,$res); + last; + } + } + } + } + } + } } } } if ($interval[0] =~ /^(\d+)/) { - my $timelimit = $1; + my $timelimit = $1; my $first_access; if ($type eq 'resource') { $first_access=&get_first_access($interval[1],$item); @@ -9051,37 +8801,10 @@ sub get_commblock_resources { my $timesup = $first_access+$timelimit; if ($timesup > $now) { my $activeblock; - if ($type eq 'resource') { - if (ref($navmap)) { - my $res = $navmap->getBySymb($item); - if ($res->answerable()) { - $activeblock = 1; - } - } - } elsif ($type eq 'map') { - my $mapsymb = &symbread($mapname,1); - if (($mapsymb) && (ref($navmap))) { - my $mapres = $navmap->getBySymb($mapsymb); - if (ref($mapres)) { - my $first = $mapres->map_start(); - my $finish = $mapres->map_finish(); - my $it = $navmap->getIterator($first,$finish,undef,0,0); - if (ref($it)) { - my $res; - while ($res = $it->next(undef,1)) { - next unless (ref($res)); - my $symb = $res->symb(); - next if (($symb eq $mapsymb) || ($symb eq '')); - @interval=&EXT("resource.0.interval",$symb); - if ($interval[1] eq 'map') { - if ($res->answerable()) { - $activeblock = 1; - last; - } - } - } - } - } + foreach my $res (@to_test) { + if ($res->answerable()) { + $activeblock = 1; + last; } } if ($activeblock) { @@ -9111,12 +8834,8 @@ sub has_comm_blocking { my @blockers; return unless ($env{'request.course.id'}); return unless ($priv eq 'bre'); + return if ($env{'user.priv.'.$env{'request.role'}} =~/evb\&([^\:]*)/); return if ($env{'request.state'} eq 'construct'); - my $courseurl = &courseid_to_courseurl($env{'request.course.id'}); - if ($env{'request.course.sec'}) { - $courseurl .= '/'.$env{'request.course.sec'}; - } - return if ($env{'user.priv.'.$env{'request.role'}.'.'.$courseurl} =~/evb\&([^\:]*)/); my %blockinfo; if (ref($blocks) eq 'HASH') { %blockinfo = &get_commblock_resources($blocks); @@ -9131,7 +8850,7 @@ sub has_comm_blocking { } if ($symb) { @symbs = ($symb); - } elsif (keys(%possibles)) { + } elsif (keys(%possibles)) { @symbs = keys(%possibles); } my $noblock; @@ -9166,7 +8885,7 @@ sub has_comm_blocking { } } } - unless ($noblock) { + unless ($noblock) { return @blockers; } return; @@ -9191,9 +8910,29 @@ sub deeplink_check { @symbs = keys(%possibles); } - my ($deeplink_symb,$allow); - if ($env{'request.deeplink.login'}) { - $deeplink_symb = &Apache::loncommon::deeplink_login_symb($cnum,$cdom); + my ($login,$switchrole,$allow); + if ($env{'request.deeplink.login'} =~ m{^\Q/tiny/$cdom/\E(\w+)$}) { + my $key = $1; + my $tinyurl; + my ($result,$cached)=&Apache::lonnet::is_cached_new('tiny',$cdom."\0".$key); + if (defined($cached)) { + $tinyurl = $result; + } else { + my $configuname = &Apache::lonnet::get_domainconfiguser($cdom); + my %currtiny = &Apache::lonnet::get('tiny',[$key],$cdom,$configuname); + if ($currtiny{$key} ne '') { + $tinyurl = $currtiny{$key}; + &Apache::lonnet::do_cache_new('tiny',$cdom."\0".$key,$currtiny{$key},600); + } + } + if ($tinyurl ne '') { + my ($cnumreq,$posslogin) = split(/\&/,$tinyurl); + if ($cnumreq eq $cnum) { + $login = $posslogin; + } else { + $switchrole = 1; + } + } } foreach my $symb (@symbs) { last if ($allow); @@ -9201,48 +8940,34 @@ sub deeplink_check { if ($deeplink eq '') { $allow = 1; } else { - my ($state,$others,$listed,$scope,$protect) = split(/,/,$deeplink); - if ($state ne 'only') { + my ($listed,$scope,$access) = split(/,/,$deeplink); + if ($access eq 'any') { $allow = 1; - } else { - my $check_deeplink_entry; - if ($protect ne 'none') { - my ($acctype,$item) = split(/:/,$protect); - if (($acctype eq 'ltic') && ($env{'user.linkprotector'})) { - if (grep(/^\Q$item\Ec$/,split(/,/,$env{'user.linkprotector'}))) { - $check_deeplink_entry = 1 - } - } elsif (($acctype eq 'ltid') && ($env{'user.linkprotector'})) { - if (grep(/^\Q$item\Ed$/,split(/,/,$env{'user.linkprotector'}))) { - $check_deeplink_entry = 1; - } - } elsif (($acctype eq 'key') && ($env{'user.deeplinkkey'})) { - if (grep(/^\Q$item\E$/,split(/,/,$env{'user.deeplinkkey'}))) { - $check_deeplink_entry = 1; - } - } - } - if (($protect eq 'none') || ($check_deeplink_entry)) { + } elsif ($login) { + if ($access eq 'only') { if ($scope eq 'res') { - if ($symb eq $deeplink_symb) { + if ($symb eq $login) { $allow = 1; } - } elsif (($scope eq 'map') || ($scope eq 'rec')) { - my ($map_from_symb,$map_from_login); - $map_from_symb = &deversion((&decode_symb($symb))[0]); - if ($deeplink_symb =~ /\.(page|sequence)$/) { - $map_from_login = &deversion((&decode_symb($deeplink_symb))[2]); - } else { - $map_from_login = &deversion((&decode_symb($deeplink_symb))[0]); + } elsif ($scope eq 'map') { +#FIXME Compare map for $env{'request.deeplink.login'} with map for $symb + } elsif ($scope eq 'rec') { +#FIXME Recurse up for $env{'request.deeplink.login'} with map for $symb + } + } else { + my ($acctype,$item) = split(/:/,$access); + if (($acctype eq 'lti') && ($env{'user.linkprotector'})) { + if (grep(/^\Q$item\E$/,split(/,/,$env{'user.linkprotector'}))) { + my %tinyurls = &get('tiny',[$symb],$cdom,$cnum); + if (grep(/\Q$tinyurls{$symb}\E$/,split(/,/,$env{'user.linkproturis'}))) { + $allow = 1; + } } - if (($map_from_symb) && ($map_from_login)) { - if ($map_from_symb eq $map_from_login) { + } elsif (($acctype eq 'key') && ($env{'user.deeplinkkey'})) { + if (grep(/^\Q$item\E$/,split(/,/,$env{'user.deeplinkkey'}))) { + my %tinyurls = &get('tiny',[$symb],$cdom,$cnum); + if (grep(/\Q$tinyurls{$symb}\E$/,split(/,/,$env{'user.keyedlinkuri'}))) { $allow = 1; - } elsif ($scope eq 'rec') { - my @recurseup = &get_map_hierarchy($map_from_symb,$env{'request.course.id'}); - if (grep(/^\Q$map_from_login\E$/,@recurseup)) { - $allow = 1; - } } } } @@ -9254,7 +8979,7 @@ sub deeplink_check { return 1; } -# -------------------------------- Deversion and split uri into path an filename +# -------------------------------- Deversion and split uri into path an filename # # Removes the version from a URI and @@ -9380,9 +9105,9 @@ sub metadata_query { my @server_list = (defined($server_array) ? @$server_array : keys(%libserv) ); for my $server (@server_list) { - my $domains = ''; + my $domains = ''; if (ref($domains_hash) eq 'HASH') { - $domains = $domains_hash->{$server}; + $domains = $domains_hash->{$server}; } unless ($custom or $customshow) { my $reply=&reply("querysend:".&escape($query).':::'.&escape($domains),$server); @@ -9515,7 +9240,7 @@ sub fetch_enrollment_query { } sub get_query_reply { - my ($queryid,$sleep,$loopmax) = @_; + my ($queryid,$sleep,$loopmax) = @_;; if (($sleep eq '') || ($sleep !~ /^\d+\.?\d*$/)) { $sleep = 0.2; } @@ -9648,25 +9373,6 @@ sub auto_validate_instcode { return ($outcome,$description,$defaultcredits); } -sub auto_validate_inst_crosslist { - my ($cnum,$cdom,$instcode,$inst_xlist,$coowner) = @_; - my ($homeserver,$response); - if (($cdom =~ /^$match_domain$/) && ($cnum =~ /^$match_courseid$/)) { - $homeserver = &homeserver($cnum,$cdom); - } - if (!defined($homeserver)) { - if ($cdom =~ /^$match_domain$/) { - $homeserver = &domain($cdom,'primary'); - } - } - unless (($homeserver eq '') || ($homeserver eq 'no_host')) { - $response=&reply('autovalidateinstcrosslist:'.$cdom.':'. - &escape($instcode).':'.&escape($inst_xlist).':'. - &escape($coowner),$homeserver); - } - return $response; -} - sub auto_create_password { my ($cnum,$cdom,$authparam,$udom) = @_; my ($homeserver,$response); @@ -9938,38 +9644,6 @@ sub auto_validate_class_sec { return $response; } -sub auto_instsec_reformat { - my ($cdom,$action,$instsecref) = @_; - return unless(($action eq 'clutter') || ($action eq 'declutter')); - my @homeservers; - if (defined(&domain($cdom,'primary'))) { - push(@homeservers,&domain($cdom,'primary')); - } else { - my %servers = &get_servers($cdom,'library'); - foreach my $tryserver (keys(%servers)) { - if (!grep(/^\Q$tryserver\E$/,@homeservers)) { - push(@homeservers,$tryserver); - } - } - } - my $response; - my %reformatted = %{$instsecref}; - foreach my $server (@homeservers) { - if (ref($instsecref) eq 'HASH') { - my $info = &freeze_escape($instsecref); - my $response=&reply('autoinstsecreformat:'.$cdom.':'. - $action.':'.$info,$server); - next if ($response =~ /(con_lost|error|no_such_host|refused|unknown_command)/); - my @items = split(/&/,$response); - foreach my $item (@items) { - my ($key,$value) = split(/=/,$item); - $reformatted{&unescape($key)} = &thaw_unescape($value); - } - } - } - return %reformatted; -} - sub auto_validate_instclasses { my ($cdom,$cnum,$owners,$classesref) = @_; my ($homeserver,%validations); @@ -10013,7 +9687,8 @@ sub auto_crsreq_update { ':'.&escape($action).':'.&escape($ownername).':'. &escape($ownerdomain).':'.&escape($fullname).':'. &escape($title).':'.&escape($code).':'. - &escape($accessstart).':'.&escape($accessend).':'.$info,$homeserver); + &escape($accessstart).':'.&escape($accessend).':'.$info, + $homeserver); unless ($response =~ /(con_lost|error|no_such_host|refused)/) { my @items = split(/&/,$response); foreach my $item (@items) { @@ -10273,6 +9948,7 @@ sub plaintext { my %rolenames = ( Course => 'std', Community => 'alt1', + Placement => 'std', ); if ($cid ne '') { if ($env{'course.'.$cid.'.'.$short.'.plaintext'} ne '') { @@ -10354,7 +10030,7 @@ sub assignrole { } if ($refused) { my ($cdom,$cnum) = ($cwosec =~ m{^/?($match_domain)/($match_courseid)$}); - if (!$selfenroll && $context eq 'course') { + if (!$selfenroll && (($context eq 'course') || ($context eq 'ltienroll' && $env{'request.lti.login'}))) { my %crsenv; if ($role eq 'cc' || $role eq 'co') { %crsenv = &userenvironment($cdom,$cnum,('internal.courseowner')); @@ -10398,7 +10074,7 @@ sub assignrole { } } } elsif ($context eq 'requestauthor') { - if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'}) && + if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'}) && ($url eq '/'.$udom.'/') && ($role eq 'au')) { if ($env{'environment.requestauthor'} eq 'automatic') { $refused = ''; @@ -10406,13 +10082,13 @@ sub assignrole { my %domdefaults = &get_domain_defaults($udom); if (ref($domdefaults{'requestauthor'}) eq 'HASH') { my $checkbystatus; - if ($env{'user.adv'}) { + if ($env{'user.adv'}) { my $disposition = $domdefaults{'requestauthor'}{'_LC_adv'}; if ($disposition eq 'automatic') { $refused = ''; } elsif ($disposition eq '') { $checkbystatus = 1; - } + } } else { $checkbystatus = 1; } @@ -10500,7 +10176,7 @@ sub assignrole { $context); } elsif (($role eq 'ca') || ($role eq 'aa')) { &coauthorrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag, - $context); + $context); } if ($role eq 'cc') { &autoupdate_coowners($url,$end,$start,$uname,$udom); @@ -10518,23 +10194,11 @@ sub autoupdate_coowners { if ($domdesign{$cdom.'.autoassign.co-owners'}) { my %coursehash = &coursedescription($cdom.'_'.$cnum); my $instcode = $coursehash{'internal.coursecode'}; - my $xlists = $coursehash{'internal.crosslistings'}; if ($instcode ne '') { if (($start && $start <= $now) && ($end == 0) || ($end > $now)) { unless ($coursehash{'internal.courseowner'} eq $uname.':'.$udom) { my ($delcoowners,@newcoowners,$putresult,$delresult,$coowners); my ($result,$desc) = &auto_validate_instcode($cnum,$cdom,$instcode,$uname.':'.$udom); - unless ($result eq 'valid') { - if ($xlists ne '') { - foreach my $xlist (split(',',$xlists)) { - my ($inst_crosslist,$lcsec) = split(':',$xlist); - $result = - &auto_validate_inst_crosslist($cnum,$cdom,$instcode, - $inst_crosslist,$uname.':'.$udom); - last if ($result eq 'valid'); - } - } - } if ($result eq 'valid') { if ($coursehash{'internal.co-owners'}) { foreach my $coowner (split(',',$coursehash{'internal.co-owners'})) { @@ -10547,15 +10211,17 @@ sub autoupdate_coowners { } else { push(@newcoowners,$uname.':'.$udom); } - } elsif ($coursehash{'internal.co-owners'}) { - foreach my $coowner (split(',',$coursehash{'internal.co-owners'})) { - unless ($coowner eq $uname.':'.$udom) { - push(@newcoowners,$coowner); + } else { + if ($coursehash{'internal.co-owners'}) { + foreach my $coowner (split(',',$coursehash{'internal.co-owners'})) { + unless ($coowner eq $uname.':'.$udom) { + push(@newcoowners,$coowner); + } + } + unless (@newcoowners > 0) { + $delcoowners = 1; + $coowners = ''; } - } - unless (@newcoowners > 0) { - $delcoowners = 1; - $coowners = ''; } } if (@newcoowners || $delcoowners) { @@ -10630,14 +10296,13 @@ sub modifyuserauth { ' in domain '.$env{'request.role.domain'}); my $reply=&reply('encrypt:changeuserauth:'.$udom.':'.$uname.':'.$umode.':'. &escape($upass),$uhome); - my $ip = &get_requestor_ip(); &log($env{'user.domain'},$env{'user.name'},$env{'user.home'}, 'Authentication changed for '.$udom.', '.$uname.', '.$umode. - '(Remote '.$ip.'): '.$reply); + '(Remote '.$ENV{'REMOTE_ADDR'}.'): '.$reply); &log($udom,,$uname,$uhome, 'Authentication changed by '.$env{'user.domain'}.', '. $env{'user.name'}.', '.$umode. - '(Remote '.$ip.'): '.$reply); + '(Remote '.$ENV{'REMOTE_ADDR'}.'): '.$reply); unless ($reply eq 'ok') { &logthis('Authentication mode error: '.$reply); return 'error: '.$reply; @@ -10720,7 +10385,7 @@ sub modifyuser { 'current user id "'.$uidhash{$uname}.'".'; } } else { - &idput($udom,($uname => $uid)); + &idput($udom,{$uname => $uid},$uhome,'ids'); } } # -------------------------------------------------------------- Add names, etc @@ -10845,7 +10510,7 @@ sub modifystudent { # student's environment $uid = undef if (!$forceid); $reply = &modify_student_enrollment($udom,$uname,$uid,$first,$middle,$last, - $gene,$usec,$end,$start,$type,$locktype, + $gene,$usec,$end,$start,$type,$locktype, $cid,$selfenroll,$context,$credits,$instsec); return $reply; } @@ -11127,6 +10792,7 @@ sub generate_coursenum { sub is_course { my ($cdom, $cnum) = scalar(@_) == 1 ? ($_[0] =~ /^($match_domain)_($match_courseid)$/) : @_; + return unless (($cdom =~ /^$match_domain$/) && ($cnum =~ /^$match_courseid$/)); my $uhome=&homeserver($cnum,$cdom); my $iscourse; @@ -11145,7 +10811,7 @@ sub is_course { &do_cache_new('iscourse',$hashid,$iscourse,3600); } } - return unless($iscourse); + return unless ($iscourse); return wantarray ? ($cdom, $cnum) : $cdom.'_'.$cnum; } @@ -11162,7 +10828,7 @@ sub store_userdata { if (($uhome eq '') || ($uhome eq 'no_host')) { $result = 'error: no_host'; } else { - $storehash->{'ip'} = &get_requestor_ip(); + $storehash->{'ip'} = $ENV{'REMOTE_ADDR'}; $storehash->{'host'} = $perlvar{'lonHostID'}; my $namevalue=''; @@ -11344,6 +11010,90 @@ sub files_not_in_path { return (@return_files); } +#------------------------------Submitted/Handedback Portfolio Files Versioning + +sub portfiles_versioning { + my ($symb,$domain,$stu_name,$portfiles,$versioned_portfiles) = @_; + my $portfolio_root = '/userfiles/portfolio'; + return unless ((ref($portfiles) eq 'ARRAY') && (ref($versioned_portfiles) eq 'ARRAY')); + foreach my $file (@{$portfiles}) { + &unmark_as_readonly($domain,$stu_name,[$symb,$env{'request.course.id'}],$file); + my ($directory,$answer_file) =($file =~ /^(.*?)([^\/]*)$/); + my ($answer_name,$answer_ver,$answer_ext) = &file_name_version_ext($answer_file); + my $getpropath = 1; + my ($dir_list,$listerror) = &dirlist($portfolio_root.$directory,$domain, + $stu_name,$getpropath); + my $version = &get_next_version($answer_name,$answer_ext,$dir_list); + my $new_answer = + &version_selected_portfile($domain,$stu_name,$directory,$answer_file,$version); + if ($new_answer ne 'problem getting file') { + push(@{$versioned_portfiles}, $directory.$new_answer); + &mark_as_readonly($domain,$stu_name,[$directory.$new_answer], + [$symb,$env{'request.course.id'},'graded']); + } + } +} + +sub get_next_version { + my ($answer_name, $answer_ext, $dir_list) = @_; + my $version; + if (ref($dir_list) eq 'ARRAY') { + foreach my $row (@{$dir_list}) { + my ($file) = split(/\&/,$row,2); + my ($file_name,$file_version,$file_ext) = + &file_name_version_ext($file); + if (($file_name eq $answer_name) && + ($file_ext eq $answer_ext)) { + # gets here if filename and extension match, + # regardless of version + if ($file_version ne '') { + # a versioned file is found so save it for later + if ($file_version > $version) { + $version = $file_version; + } + } + } + } + } + $version ++; + return($version); +} + +sub version_selected_portfile { + my ($domain,$stu_name,$directory,$file_name,$version) = @_; + my ($answer_name,$answer_ver,$answer_ext) = + &file_name_version_ext($file_name); + my $new_answer; + $env{'form.copy'} = + &getfile("/uploaded/$domain/$stu_name/portfolio$directory$file_name"); + if($env{'form.copy'} eq '-1') { + $new_answer = 'problem getting file'; + } else { + $new_answer = $answer_name.'.'.$version.'.'.$answer_ext; + my $copy_result = + &finishuserfileupload($stu_name,$domain,'copy', + '/portfolio'.$directory.$new_answer); + } + undef($env{'form.copy'}); + return ($new_answer); +} + +sub file_name_version_ext { + my ($file)=@_; + my @file_parts = split(/\./, $file); + my ($name,$version,$ext); + if (@file_parts > 1) { + $ext=pop(@file_parts); + if (@file_parts > 1 && $file_parts[-1] =~ /^\d+$/) { + $version=pop(@file_parts); + } + $name=join('.',@file_parts); + } else { + $name=join('.',@file_parts); + } + return($name,$version,$ext); +} + #----------------------------------------------Get portfolio file permissions sub get_portfile_permissions { @@ -11488,49 +11238,132 @@ sub modify_access_controls { } sub make_public_indefinitely { - my ($requrl) = @_; + my (@requrl) = @_; + return &automated_portfile_access('public',\@requrl); +} + +sub automated_portfile_access { + my ($accesstype,$addsref,$delsref,$info) = @_; + unless (($accesstype eq 'public') || ($accesstype eq 'ip')) { + return 'invalid'; + } + my %urls; + if (ref($addsref) eq 'ARRAY') { + foreach my $requrl (@{$addsref}) { + if (&is_portfolio_url($requrl)) { + unless (exists($urls{$requrl})) { + $urls{$requrl} = 'add'; + } + } + } + } + if (ref($delsref) eq 'ARRAY') { + foreach my $requrl (@{$delsref}) { + if (&is_portfolio_url($requrl)) { + unless (exists($urls{$requrl})) { + $urls{$requrl} = 'delete'; + } + } + } + } + unless (keys(%urls)) { + return 'invalid'; + } + my $ip; + if ($accesstype eq 'ip') { + if (ref($info) eq 'HASH') { + if ($info->{'ip'} ne '') { + $ip = $info->{'ip'}; + } + } + if ($ip eq '') { + return 'invalid'; + } + } + my $errors; my $now = time; - my $action = 'activate'; - my $aclnum = 0; - if (&is_portfolio_url($requrl)) { + my %current_perms; + foreach my $requrl (sort(keys(%urls))) { + my $action; + if ($urls{$requrl} eq 'add') { + $action = 'activate'; + } else { + $action = 'none'; + } + my $aclnum = 0; my (undef,$udom,$unum,$file_name,$group) = &parse_portfolio_url($requrl); - my $current_perms = &get_portfile_permissions($udom,$unum); - my %access_controls = &get_access_controls($current_perms, + unless (exists($current_perms{$unum.':'.$udom})) { + $current_perms{$unum.':'.$udom} = &get_portfile_permissions($udom,$unum); + } + my %access_controls = &get_access_controls($current_perms{$unum.':'.$udom}, $group,$file_name); foreach my $key (keys(%{$access_controls{$file_name}})) { my ($num,$scope,$end,$start) = ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/); - if ($scope eq 'public') { - if ($start <= $now && $end == 0) { - $action = 'none'; - } else { + if ($scope eq $accesstype) { + if (($start <= $now) && ($end == 0)) { + if ($accesstype eq 'ip') { + if (ref($access_controls{$file_name}{$key}) eq 'HASH') { + if (ref($access_controls{$file_name}{$key}{'ip'}) eq 'ARRAY') { + if (grep(/^\Q$ip\E$/,@{$access_controls{$file_name}{$key}{'ip'}})) { + if ($urls{$requrl} eq 'add') { + $action = 'none'; + last; + } else { + $action = 'delete'; + $aclnum = $num; + last; + } + } + } + } + } elsif ($accesstype eq 'public') { + if ($urls{$requrl} eq 'add') { + $action = 'none'; + last; + } else { + $action = 'delete'; + $aclnum = $num; + last; + } + } + } elsif ($accesstype eq 'public') { $action = 'update'; $aclnum = $num; + last; } - last; } } if ($action eq 'none') { - return 'ok'; + next; } else { my %changes; my $newend = 0; my $newstart = $now; - my $newkey = $aclnum.':public_'.$newend.'_'.$newstart; + my $newkey = $aclnum.':'.$accesstype.'_'.$newend.'_'.$newstart; $changes{$action}{$newkey} = { - type => 'public', + type => $accesstype, time => { start => $newstart, end => $newend, }, }; + if ($accesstype eq 'ip') { + $changes{$action}{$newkey}{'ip'} = [$ip]; + } my ($outcome,$deloutcome,$new_values,$translation) = &modify_access_controls($file_name,\%changes,$udom,$unum); - return $outcome; + unless ($outcome eq 'ok') { + $errors .= $outcome.' '; + } } + } + if ($errors) { + $errors =~ s/\s$//; + return $errors; } else { - return 'invalid'; + return 'ok'; } } @@ -11735,11 +11568,12 @@ sub dirlist { foreach my $user (sort(keys(%allusers))) { push(@alluserslist,$user.'&user'); } + if (!%listerror) { # no errors return (\@alluserslist); } elsif (scalar(keys(%servers)) == 1) { - # one library server, one error + # one library server, one error my ($key) = keys(%listerror); return (\@alluserslist, $listerror{$key}); } elsif ( grep { $_ eq 'con_lost' } values(%listerror) ) { @@ -11748,7 +11582,7 @@ sub dirlist { return (\@alluserslist, 'con_lost'); } else { # multiple library servers and no con_lost -> data should be - # complete. + # complete. return (\@alluserslist); } @@ -11824,6 +11658,115 @@ sub stat_file { return (); } +# --------------------------------------------------------- recursedirs +# Recursive function to traverse either a specific user's Authoring Space +# or corresponding Published Resource Space, and populate the hash ref: +# $dirhashref with URLs of all directories, and if $filehashref hash +# ref arg is provided, the URLs of any files, excluding versioned, .meta, +# or .rights files in resource space, and .meta, .save, .log, and .bak +# files in Authoring Space. +# +# Inputs: +# +# $is_home - true if current server is home server for user's space +# $context - either: priv, or res respectively for Authoring or Resource Space. +# $docroot - Document root (i.e., /home/httpd/html +# $toppath - Top level directory (i.e., /res/$dom/$uname or /priv/$dom/$uname +# $relpath - Current path (relative to top level). +# $dirhashref - reference to hash to populate with URLs of directories (Required) +# $filehashref - reference to hash to populate with URLs of files (Optional) +# +# Returns: nothing +# +# Side Effects: populates $dirhashref, and $filehashref (if provided). +# +# Currently used by interface/londocs.pm to create linked select boxes for +# directory and filename to import a Course "Author" resource into a course, and +# also to create linked select boxes for Authoring Space and Directory to choose +# save location for creation of a new "standard" problem from the Course Editor. +# + +sub recursedirs { + my ($is_home,$context,$docroot,$toppath,$relpath,$dirhashref,$filehashref) = @_; + return unless (ref($dirhashref) eq 'HASH'); + my $currpath = $docroot.$toppath; + if ($relpath) { + $currpath .= "/$relpath"; + } + my $savefile; + if (ref($filehashref)) { + $savefile = 1; + } + if ($is_home) { + if (opendir(my $dirh,$currpath)) { + foreach my $item (sort { lc($a) cmp lc($b) } grep(!/^\.+$/,readdir($dirh))) { + next if ($item eq ''); + if (-d "$currpath/$item") { + my $newpath; + if ($relpath) { + $newpath = "$relpath/$item"; + } else { + $newpath = $item; + } + $dirhashref->{&Apache::lonlocal::js_escape($newpath)} = 1; + &recursedirs($is_home,$context,$docroot,$toppath,$newpath,$dirhashref,$filehashref); + } elsif ($savefile) { + if ($context eq 'priv') { + unless ($item =~ /\.(meta|save|log|bak|DS_Store)$/) { + $filehashref->{&Apache::lonlocal::js_escape($relpath)}{$item} = 1; + } + } else { + unless (($item =~ /\.meta$/) || ($item =~ /\.\d+\.\w+$/) || ($item =~ /\.rights$/)) { + $filehashref->{&Apache::lonlocal::js_escape($relpath)}{$item} = 1; + } + } + } + } + closedir($dirh); + } + } else { + my ($dirlistref,$listerror) = + &dirlist($toppath.$relpath); + my @dir_lines; + my $dirptr=16384; + if (ref($dirlistref) eq 'ARRAY') { + foreach my $dir_line (sort + { + my ($afile)=split('&',$a,2); + my ($bfile)=split('&',$b,2); + return (lc($afile) cmp lc($bfile)); + } (@{$dirlistref})) { + my ($item,$dom,undef,$testdir,undef,undef,undef,undef,$size,undef,$mtime,undef,undef,undef,$obs,undef) = + split(/\&/,$dir_line,16); + $item =~ s/\s+$//; + next if (($item =~ /^\.\.?$/) || ($obs)); + if ($dirptr&$testdir) { + my $newpath; + if ($relpath) { + $newpath = "$relpath/$item"; + } else { + $relpath = '/'; + $newpath = $item; + } + $dirhashref->{&Apache::lonlocal::js_escape($newpath)} = 1; + &recursedirs($is_home,$context,$docroot,$toppath,$newpath,$dirhashref,$filehashref); + } elsif ($savefile) { + if ($context eq 'priv') { + unless ($item =~ /\.(meta|save|log|bak|DS_Store)$/) { + $filehashref->{$relpath}{$item} = 1; + } + } else { + unless (($item =~ /\.meta$/) || ($item =~ /\.\d+\.\w+$/)) { + $filehashref->{$relpath}{$item} = 1; + } + } + } + } + } + } + return; +} + # -------------------------------------------------------- Value of a Condition # gets the value of a specific preevaluated condition @@ -11987,7 +11930,14 @@ sub get_userresdata { # Parameters: # $name - Course/user name. # $domain - Name of the domain the user/course is registered on. -# $type - Type of thing $name is (must be 'course' or 'user' +# $type - Type of thing $name is (must be 'course' or 'user') +# $mapp - decluttered URL of enclosing map +# $recursed - Ref to scalar -- set to 1, if nested maps have been recursed. +# $recurseup - Ref to array of map URLs, starting with map containing +# $mapp up through hierarchy of nested maps to top level map. +# $courseid - CourseID (first part of param identifier). +# $modifier - Middle part of param identifier. +# $what - Last part of param identifier. # @which - Array of names of resources desired. # Returns: # The value of the first reasource in @which that is found in the @@ -11997,7 +11947,8 @@ sub get_userresdata { # 'user', an undefined reference is returned. # If none of the resources are found, an undef is returned sub resdata { - my ($name,$domain,$type,@which)=@_; + my ($name,$domain,$type,$mapp,$recursed,$recurseup,$courseid, + $modifier,$what,@which)=@_; my $result; if ($type eq 'course') { $result=&get_courseresdata($name,$domain); @@ -12006,7 +11957,21 @@ sub resdata { } if (!ref($result)) { return $result; } foreach my $item (@which) { - if (defined($result->{$item->[0]})) { + if ($item->[1] eq 'course') { + if ((ref($recurseup) eq 'ARRAY') && (ref($recursed) eq 'SCALAR')) { + unless ($$recursed) { + @{$recurseup} = &get_map_hierarchy($mapp,$courseid); + $$recursed = 1; + } + foreach my $item (@${recurseup}) { + my $norecursechk=$courseid.$modifier.$item.'___(all).'.$what; + last if (defined($result->{$norecursechk})); + my $recursechk=$courseid.$modifier.$item.'___(rec).'.$what; + if (defined($result->{$recursechk})) { return [$result->{$recursechk},'map']; } + } + } + } + if (defined($result->{$item->[0]})) { return [$result->{$item->[0]},$item->[1]]; } } @@ -12015,22 +11980,15 @@ sub resdata { sub get_domain_lti { my ($cdom,$context) = @_; - my ($name,$cachename,%lti); + my ($name,%lti); if ($context eq 'consumer') { $name = 'ltitools'; } elsif ($context eq 'provider') { $name = 'lti'; - } elsif ($context eq 'linkprot') { - $name = 'ltisec'; } else { return %lti; } - if ($context eq 'linkprot') { - $cachename = $context; - } else { - $cachename = $name; - } - my ($result,$cached)=&is_cached_new($cachename,$cdom); + my ($result,$cached)=&is_cached_new($name,$cdom); if (defined($cached)) { if (ref($result) eq 'HASH') { %lti = %{$result}; @@ -12038,218 +11996,43 @@ sub get_domain_lti { } else { my %domconfig = &get_dom('configuration',[$name],$cdom); if (ref($domconfig{$name}) eq 'HASH') { - if ($context eq 'linkprot') { - if (ref($domconfig{$name}{'linkprot'}) eq 'HASH') { - %lti = %{$domconfig{$name}{'linkprot'}}; - } - } else { - %lti = %{$domconfig{$name}}; - } - } - my $cachetime = 24*60*60; - &do_cache_new($cachename,$cdom,\%lti,$cachetime); - } - return %lti; -} - -sub get_course_lti { - my ($cnum,$cdom,$context) = @_; - my ($name,$cachename,%lti); - if ($context eq 'consumer') { - $name = 'ltitools'; - $cachename = 'courseltitools'; - } elsif ($context eq 'provider') { - $name = 'lti'; - $cachename = 'courselti'; - } else { - return %lti; - } - my $hashid=$cdom.'_'.$cnum; - my ($result,$cached)=&is_cached_new($cachename,$hashid); - if (defined($cached)) { - if (ref($result) eq 'HASH') { - %lti = %{$result}; - } - } else { - %lti = &dump($name,$cdom,$cnum,undef,undef,undef,1); - my $cachetime = 24*60*60; - &do_cache_new($cachename,$hashid,\%lti,$cachetime); - } - return %lti; -} - -sub courselti_itemid { - my ($cnum,$cdom,$url,$method,$params,$context) = @_; - my ($chome,$itemid); - $chome = &homeserver($cnum,$cdom); - return if ($chome eq 'no_host'); - if (ref($params) eq 'HASH') { - my $rep; - if (grep { $_ eq $chome } current_machine_ids()) { - $rep = LONCAPA::Lond::crslti_itemid($cdom,$cnum,$url,$method,$params,$perlvar{'lonVersion'}); - } else { - my $escurl = &escape($url); - my $escmethod = &escape($method); - my $items = &freeze_escape($params); - $rep = &reply("encrypt:lti:$cdom:$cnum:$context:$escurl:$escmethod:$items",$chome); - } - unless (($rep=~/^(refused|rejected|error)/) || ($rep eq 'con_lost') || - ($rep eq 'unknown_cmd')) { - $itemid = $rep; - } - } - return $itemid; -} - -sub domainlti_itemid { - my ($cdom,$url,$method,$params,$context) = @_; - my ($primary_id,$itemid); - $primary_id = &domain($cdom,'primary'); - return if ($primary_id eq ''); - if (ref($params) eq 'HASH') { - my $rep; - if (grep { $_ eq $primary_id } current_machine_ids()) { - $rep = LONCAPA::Lond::domlti_itemid($cdom,$context,$url,$method,$params,$perlvar{'lonVersion'}); - } else { - my $cnum = ''; - my $escurl = &escape($url); - my $escmethod = &escape($method); - my $items = &freeze_escape($params); - $rep = &reply("encrypt:lti:$cdom:$cnum:$context:$escurl:$escmethod:$items",$primary_id); - } - unless (($rep=~/^(refused|rejected|error)/) || ($rep eq 'con_lost') || - ($rep eq 'unknown_cmd')) { - $itemid = $rep; - } - } - return $itemid; -} - -sub get_ltitools_id { - my ($context,$cdom,$cnum,$title) = @_; - my ($lockhash,$tries,$gotlock,$id,$error); - - # get lock on ltitools db - $lockhash = { - lock => $env{'user.name'}. - ':'.$env{'user.domain'}, - }; - $tries = 0; - if ($context eq 'domain') { - $gotlock = &newput_dom('ltitools',$lockhash,$cdom); - } else { - $gotlock = &newput('ltitools',$lockhash,$cdom,$cnum); - } - while (($gotlock ne 'ok') && ($tries<10)) { - $tries ++; - sleep (0.1); - if ($context eq 'domain') { - $gotlock = &newput_dom('ltitools',$lockhash,$cdom); - } else { - $gotlock = &newput('ltitools',$lockhash,$cdom,$cnum); - } - } - if ($gotlock eq 'ok') { - my %currids; - if ($context eq 'domain') { - %currids = &dump_dom('ltitools',$cdom); - } else { - %currids = &dump('ltitools',$cdom,$cnum); - } - if ($currids{'lock'}) { - delete($currids{'lock'}); - if (keys(%currids)) { - my @curr = sort { $a <=> $b } keys(%currids); - if ($curr[-1] =~ /^\d+$/) { - $id = 1 + $curr[-1]; - } - } else { - $id = 1; - } - if ($id) { - if ($context eq 'domain') { - unless (&newput_dom('ltitools',{ $id => $title },$cdom) eq 'ok') { - $error = 'nostore'; - } - } else { - unless (&newput('ltitools',{ $id => $title },$cdom,$cnum) eq 'ok') { - $error = 'nostore'; - } - } - } else { - $error = 'nonumber'; - } - } - my $dellockoutcome; - if ($context eq 'domain') { - $dellockoutcome = &del_dom('ltitools',['lock'],$cdom); - } else { - $dellockoutcome = &del('ltitools',['lock'],$cdom,$cnum); - } - } else { - $error = 'nolock'; - } - return ($id,$error); -} - -sub count_supptools { - my ($cnum,$cdom,$ignorecache,$reload)=@_; - my $hashid=$cnum.':'.$cdom; - my ($numexttools,$cached); - unless ($ignorecache) { - ($numexttools,$cached) = &is_cached_new('supptools',$hashid); - } - unless (defined($cached)) { - my $chome=&homeserver($cnum,$cdom); - $numexttools = 0; - unless ($chome eq 'no_host') { - my ($supplemental) = &Apache::loncommon::get_supplemental($cnum,$cdom,$reload); - if (ref($supplemental) eq 'HASH') { - if ((ref($supplemental->{'ids'}) eq 'HASH') && (ref($supplemental->{'hidden'}) eq 'HASH')) { - foreach my $key (keys(%{$supplemental->{'ids'}})) { - if ($key =~ m{^/adm/$cdom/$cnum/\d+/ext\.tool$}) { - $numexttools ++; + %lti = %{$domconfig{$name}}; + my %encdomconfig = &get_dom('encconfig',[$name],$cdom); + if (ref($encdomconfig{$name}) eq 'HASH') { + foreach my $id (keys(%lti)) { + if (ref($encdomconfig{$name}{$id}) eq 'HASH') { + foreach my $item ('key','secret') { + $lti{$id}{$item} = $encdomconfig{$name}{$id}{$item}; } } } } } - &do_cache_new('supptools',$hashid,$numexttools,600); + my $cachetime = 24*60*60; + &do_cache_new($name,$cdom,\%lti,$cachetime); } - return $numexttools; + return %lti; } -sub has_unhidden_suppfiles { - my ($cnum,$cdom,$ignorecache,$possdel)=@_; +sub get_numsuppfiles { + my ($cnum,$cdom,$ignorecache)=@_; my $hashid=$cnum.':'.$cdom; - my ($showsupp,$cached); + my ($suppcount,$cached); unless ($ignorecache) { - ($showsupp,$cached) = &is_cached_new('showsupp',$hashid); + ($suppcount,$cached) = &is_cached_new('suppcount',$hashid); } unless (defined($cached)) { my $chome=&homeserver($cnum,$cdom); unless ($chome eq 'no_host') { - my ($supplemental) = &Apache::loncommon::get_supplemental($cnum,$cdom,$ignorecache,$possdel); - if (ref($supplemental) eq 'HASH') { - if ((ref($supplemental->{'ids'}) eq 'HASH') && (ref($supplemental->{'hidden'}) eq 'HASH')) { - foreach my $key (keys(%{$supplemental->{'ids'}})) { - next if ($key =~ /\.sequence$/); - if (ref($supplemental->{'ids'}->{$key}) eq 'ARRAY') { - foreach my $id (@{$supplemental->{'ids'}->{$key}}) { - unless ($supplemental->{'hidden'}->{$id}) { - $showsupp = 1; - last; - } - } - } - last if ($showsupp); - } - } - } + ($suppcount,my $supptools,my $errors) = (0,0,0); + my $suppmap = 'supplemental.sequence'; + ($suppcount,$supptools,$errors) = + &Apache::loncommon::recurse_supplemental($cnum,$cdom,$suppmap,$suppcount, + $supptools,$errors); } - &do_cache_new('showsupp',$hashid,$showsupp,600); + &do_cache_new('suppcount',$hashid,$suppcount,600); } - return $showsupp; + return $suppcount; } # @@ -12322,7 +12105,7 @@ sub EXT { if ( (defined($Apache::lonhomework::parsing_a_problem) || defined($Apache::lonhomework::parsing_a_task)) && - ($symbparm eq &symbread()) ) { + ($symbparm eq &symbread()) ) { # if we are in the middle of processing the resource the # get the value we are planning on committing if (defined($Apache::lonhomework::results{$qualifierrest})) { @@ -12443,23 +12226,22 @@ sub EXT { } } - my ($section, $group, @groups); - my ($courselevelm,$courselevel); + my ($section, $group, @groups, @recurseup, $recursed); + my ($courselevelm,$courseleveli,$courselevel,$mapp); if (($courseid eq '') && ($cid)) { $courseid = $cid; } if (($symbparm && $courseid) && - (($courseid eq $env{'request.course.id'}) || ($courseid eq $cid))) { + (($courseid eq $env{'request.course.id'}) || ($courseid eq $cid))) { #print '
'.$space.' - '.$qualifier.' - '.$spacequalifierrest; # ----------------------------------------------------- Cascading lookup scheme my $symbp=$symbparm; - my $mapp=&deversion((&decode_symb($symbp))[0]); - + $mapp=&deversion((&decode_symb($symbp))[0]); my $symbparm=$symbp.'.'.$spacequalifierrest; + my $recurseparm=$mapp.'___(rec).'.$spacequalifierrest; my $mapparm=$mapp.'___(all).'.$spacequalifierrest; - if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) { $section=$env{'request.course.sec'}; @@ -12476,17 +12258,21 @@ sub EXT { my $seclevel=$courseid.'.['.$section.'].'.$spacequalifierrest; my $seclevelr=$courseid.'.['.$section.'].'.$symbparm; + my $secleveli=$courseid.'.['.$section.'].'.$recurseparm; my $seclevelm=$courseid.'.['.$section.'].'.$mapparm; $courselevel=$courseid.'.'.$spacequalifierrest; my $courselevelr=$courseid.'.'.$symbparm; + $courseleveli=$courseid.'.'.$recurseparm; $courselevelm=$courseid.'.'.$mapparm; # ----------------------------------------------------------- first, check user - my $userreply=&resdata($uname,$udom,'user', + my $userreply=&resdata($uname,$udom,'user',$mapp,\$recursed, + \@recurseup,$courseid,'.',$spacequalifierrest, ([$courselevelr,'resource'], [$courselevelm,'map' ], + [$courseleveli,'map' ], [$courselevel, 'course' ])); if (defined($userreply)) { return &get_reply($userreply); } @@ -12494,15 +12280,18 @@ sub EXT { my $coursereply; if (@groups > 0) { $coursereply = &check_group_parms($courseid,\@groups,$symbparm, - $mapparm,$spacequalifierrest); - if (defined($coursereply)) { return &get_reply($coursereply); } + $recurseparm,$mapparm,$spacequalifierrest, + $mapp,\$recursed,\@recurseup); + if (defined($coursereply)) { return &get_reply($coursereply); } } $coursereply=&resdata($env{'course.'.$courseid.'.num'}, $env{'course.'.$courseid.'.domain'}, - 'course', + 'course',$mapp,\$recursed,\@recurseup, + $courseid,'.['.$section.'].',$spacequalifierrest, ([$seclevelr, 'resource'], [$seclevelm, 'map' ], + [$secleveli, 'map' ], [$seclevel, 'course' ], [$courselevelr,'resource'])); if (defined($coursereply)) { return &get_reply($coursereply); } @@ -12519,10 +12308,10 @@ sub EXT { if ($thisparm) { return &get_reply([$thisparm,'resource']); } } # ------------------------------------------ fourth, look in resource metadata - + my $what = $spacequalifierrest; - $what=~s/\./\_/; - my $filename; + $what=~s/\./\_/; + my $filename; if (!$symbparm) { $symbparm=&symbread(); } if ($symbparm) { $filename=(&decode_symb($symbparm))[2]; @@ -12543,8 +12332,10 @@ sub EXT { $courseid eq $env{'request.course.id'}) { my $coursereply=&resdata($env{'course.'.$courseid.'.num'}, $env{'course.'.$courseid.'.domain'}, - 'course', + 'course',$mapp,\$recursed,\@recurseup, + $courseid,'.',$spacequalifierrest, ([$courselevelm,'map' ], + [$courseleveli,'map' ], [$courselevel, 'course'])); if (defined($coursereply)) { return &get_reply($coursereply); } } @@ -12586,7 +12377,7 @@ sub EXT { } } elsif ($realm eq 'client') { if ($space eq 'remote_addr') { - return &get_requestor_ip(); + return $ENV{'REMOTE_ADDR'}; } } return ''; @@ -12605,19 +12396,24 @@ sub get_reply { } sub check_group_parms { - my ($courseid,$groups,$symbparm,$mapparm,$what) = @_; - my @groupitems = (); - my $resultitem; - my @levels = ([$symbparm,'resource'],[$mapparm,'map'],[$what,'course']); + my ($courseid,$groups,$symbparm,$recurseparm,$mapparm,$what,$mapp, + $recursed,$recurseupref) = @_; + my @levels = ([$symbparm,'resource'],[$mapparm,'map'],[$recurseparm,'map'], + [$what,'course']); + my $coursereply; foreach my $group (@{$groups}) { + my @groupitems = (); foreach my $level (@levels) { my $item = $courseid.'.['.$group.'].'.$level->[0]; push(@groupitems,[$item,$level->[1]]); } + my $coursereply = &resdata($env{'course.'.$courseid.'.num'}, + $env{'course.'.$courseid.'.domain'}, + 'course',$mapp,$recursed,$recurseupref, + $courseid,'.['.$group.'].',$what, + @groupitems); + last if (defined($coursereply)); } - my $coursereply = &resdata($env{'course.'.$courseid.'.num'}, - $env{'course.'.$courseid.'.domain'}, - 'course',@groupitems); return $coursereply; } @@ -12764,11 +12560,11 @@ sub metadata { # gradable in the exttool_$marker.db file for the tool instance # is retrieved via &get(). # -# When lonuserstate::traceroute() calls lonnet::EXT() for +# When lonuserstate::traceroute() calls lonnet::EXT() for # hiddenresource and encrypturl (during course initialization) -# the map-level parameter for resource.0.gradable included in the +# the map-level parameter for resource.0.gradable included in the # uploaded map containing the tool will not yet have been stored -# in the user_course_parms.db file for the user's session, so in +# in the user_course_parms.db file for the user's session, so in # this case fall back to retrieving gradable status from the # exttool_$marker.db file. # @@ -12916,23 +12712,31 @@ sub metadata { # Check metadata for imported file to # see if it contained response items # + my ($origfile,@libfilekeys); my %currmetaentry = %metaentry; - my $libresponseorder = &metadata($location,'responseorder'); - my $origfile; - if ($libresponseorder ne '') { - if ($#origfiletagids<0) { - undef(%importedrespids); - undef(%importedpartids); - } - @{$importedrespids{$importid}} = split(/\s*,\s*/,$libresponseorder); - if (@{$importedrespids{$importid}} > 0) { - $importedresponses = 1; + @libfilekeys = split(/,/,&metadata($location,'keys',undef,undef,undef, + $depthcount+1)); + if (grep(/^responseorder$/,@libfilekeys)) { + my $libresponseorder = &metadata($location,'responseorder',undef,undef, + undef,$depthcount+1); + if ($libresponseorder ne '') { + if ($#origfiletagids<0) { + undef(%importedrespids); + undef(%importedpartids); + } + my @respids = split(/\s*,\s*/,$libresponseorder); + if (@respids) { + $importedrespids{$importid} = join(',',map { $importid.'_'.$_ } @respids); + } + if ($importedrespids{$importid} ne '') { + $importedresponses = 1; # We need to get the original file and the imported file to get the response order correct # Load and inspect original file - if ($#origfiletagids<0) { - my $origfilelocation=$perlvar{'lonDocRoot'}.&clutter($uri); - $origfile=&getfile($origfilelocation); - @origfiletagids=($origfile=~/<((?:\w+)response|import|part)[^>]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs); + if ($#origfiletagids<0) { + my $origfilelocation=$perlvar{'lonDocRoot'}.&clutter($uri); + $origfile=&getfile($origfilelocation); + @origfiletagids=($origfile=~/<((?:\w+)response|import|part)[^>]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs); + } } } } @@ -12940,10 +12744,7 @@ sub metadata { # hash populated for imported library file %metaentry = %currmetaentry; undef(%currmetaentry); - if ($importmode eq 'problem') { -# Import as problem/response - $unikey=&add_prefix_and_part($prefix,$token->[2]->{'part'}); - } elsif ($importmode eq 'part') { + if ($importmode eq 'part') { # Import as part(s) $importedparts=1; # We need to get the original file and the imported file to get the part order correct @@ -12958,10 +12759,23 @@ sub metadata { @origfiletagids=($origfile=~/<(part|import)[^>]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs); } } - -# Load and inspect imported file - my $impfile=&getfile($location); - my @impfilepartids=($impfile=~/]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs); + my @impfilepartids; +# If tag is included in metadata for the imported file +# get the parts in the imported file from that. + if (grep(/^partorder$/,@libfilekeys)) { + %currmetaentry = %metaentry; + my $libpartorder = &metadata($location,'partorder',undef,undef,undef, + $depthcount+1); + %metaentry = %currmetaentry; + undef(%currmetaentry); + if ($libpartorder ne '') { + @impfilepartids=split(/\s*,\s*/,$libpartorder); + } + } else { +# If no tag available, load and inspect imported file + my $impfile=&getfile($location); + @impfilepartids=($impfile=~/]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs); + } if ($#impfilepartids>=0) { # This problem had parts $importedpartids{$token->[2]->{'id'}}=join(',',@impfilepartids); @@ -12972,13 +12786,28 @@ sub metadata { $importedpartids{$token->[2]->{'id'}}=$token->[2]->{'id'}; } } else { +# Import as problem or as normal import + $unikey=&add_prefix_and_part($prefix,$token->[2]->{'part'}); + unless ($importmode eq 'problem') { # Normal import - $unikey=&add_prefix_and_part($prefix,$token->[2]->{'part'}); - if (defined($token->[2]->{'id'})) { - $unikey.='_'.$token->[2]->{'id'}; - } + if (defined($token->[2]->{'id'})) { + $unikey.='_'.$token->[2]->{'id'}; + } + } +# Check metadata for imported file to +# see if it contained parts + if (grep(/^partorder$/,@libfilekeys)) { + %currmetaentry = %metaentry; + my $libpartorder = &metadata($location,'partorder',undef,undef,undef, + $depthcount+1); + %metaentry = %currmetaentry; + undef(%currmetaentry); + if ($libpartorder ne '') { + $importedparts = 1; + $importedpartids{$token->[2]->{'id'}}=$libpartorder; + } + } } - if ($depthcount<20) { my $metadata = &metadata($uri,'keys',$toolsymb,$location,$unikey, @@ -12987,7 +12816,6 @@ sub metadata { $metaentry{':'.$meta}=$metaentry{':'.$meta}; $metathesekeys{$meta}=1; } - } } else { # @@ -13077,7 +12905,7 @@ sub metadata { $metathesekeys{'partorder'}=1; } if ($importedresponses) { -# We had imported responses and need to rebuild responseorder +# We had imported responses and need to rebuil responseorder $metaentry{':responseorder'}=''; $metathesekeys{'responseorder'}=1; } @@ -13091,12 +12919,14 @@ sub metadata { } elsif ($origfiletagids[$index] eq 'import') { if ($importedparts) { # We have imported parts at this position - $metaentry{':partorder'}.=','.$importedpartids{$origid}; + if ($importedpartids{$origid} ne '') { + $metaentry{':partorder'}.=','.$importedpartids{$origid}; + } } if ($importedresponses) { # We have imported responses at this position - if (ref($importedrespids{$origid}) eq 'ARRAY') { - $metaentry{':responseorder'}.=','.join(',',map { $origid.'_'.$_ } @{$importedrespids{$origid}}); + if ($importedrespids{$origid} ne '') { + $metaentry{':responseorder'}.=','.$importedrespids{$origid}; } } } else { @@ -13113,11 +12943,12 @@ sub metadata { $metaentry{':responseorder'}=~s/^\,//; } } - $metaentry{':keys'} = join(',',keys(%metathesekeys)); &metadata_generate_part0(\%metathesekeys,\%metaentry,$uri); $metaentry{':allpossiblekeys'}=join(',',keys(%metathesekeys)); - &do_cache_new('meta',$uri,\%metaentry,$cachetime); + unless ($liburi) { + &do_cache_new('meta',$uri,\%metaentry,$cachetime); + } # this is the end of "was not already recently cached } return $metaentry{':'.$what}; @@ -13325,68 +13156,11 @@ sub get_coursechange { } sub devalidate_coursechange_cache { - my ($cdom,$cnum)=@_; - my $hashid=$cdom.'_'.$cnum; + my ($cnum,$cdom)=@_; + my $hashid=$cnum.':'.$cdom; &devalidate_cache_new('crschange',$hashid); } -sub get_suppchange { - my ($cdom,$cnum) = @_; - if ($cdom eq '' || $cnum eq '') { - return unless ($env{'request.course.id'}); - $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; - $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; - } - my $hashid=$cdom.'_'.$cnum; - my ($change,$cached)=&is_cached_new('suppchange',$hashid); - if ((defined($cached)) && ($change ne '')) { - return $change; - } else { - my %crshash = &get('environment',['internal.supplementalchange'],$cdom,$cnum); - if ($crshash{'internal.supplementalchange'} eq '') { - $change = $env{'course.'.$cdom.'_'.$cnum.'.internal.created'}; - if ($change eq '') { - %crshash = &get('environment',['internal.created'],$cdom,$cnum); - $change = $crshash{'internal.created'}; - } - } else { - $change = $crshash{'internal.supplementalchange'}; - } - my $cachetime = 600; - &do_cache_new('suppchange',$hashid,$change,$cachetime); - } - return $change; -} - -sub devalidate_suppchange_cache { - my ($cdom,$cnum)=@_; - my $hashid=$cdom.'_'.$cnum; - &devalidate_cache_new('suppchange',$hashid); -} - -sub update_supp_caches { - my ($cdom,$cnum) = @_; - my %servers = &internet_dom_servers($cdom); - my @ids=¤t_machine_ids(); - foreach my $server (keys(%servers)) { - next if (grep(/^\Q$server\E$/,@ids)); - my $hashid=$cnum.':'.$cdom; - my $cachekey = &escape('showsupp').':'.&escape($hashid); - &remote_devalidate_cache($server,[$cachekey]); - } - &has_unhidden_suppfiles($cnum,$cdom,1,1); - &count_supptools($cnum,$cdom,1); - my $now = time; - if ($env{'request.course.id'} eq $cdom.'_'.$cnum) { - &Apache::lonnet::appenv({'request.course.suppupdated' => $now}); - } - &put('environment',{'internal.supplementalchange' => $now}, - $cdom,$cnum); - &Apache::lonnet::appenv( - {'course.'.$cdom.'_'.$cnum.'.internal.supplementalchange' => $now}); - &do_cache_new('suppchange',$cdom.'_'.$cnum,$now,600); -} - # ------------------------------------------------- Update symbolic store links sub symblist { @@ -13447,7 +13221,7 @@ sub symbverify { $ids=$bighash{'ids_'.&clutter($thisurl)}; } unless ($ids) { - my $idkey = 'ids_'.($thisurl =~ m{^/}? '' : '/').$thisurl; + my $idkey = 'ids_'.($thisurl =~ m{^/}? '' : '/').$thisurl; $ids=$bighash{$idkey}; } if ($ids) { @@ -13463,14 +13237,14 @@ sub symbverify { if (ref($encstate)) { $$encstate = $bighash{'encrypted_'.$id}; } - if (($env{'request.role.adv'}) || - ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) || + if (($env{'request.role.adv'}) || + ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) || ($thisurl eq '/adm/navmaps')) { - $okay=1; + $okay=1; last; - } - } - } + } + } + } } untie(%bighash); } @@ -13558,8 +13332,8 @@ sub symbread { unless ($thisfn) { if ($env{'request.symb'}) { return $env{$cache_str}=&symbclean($env{'request.symb'}); - } - $thisfn=$env{'request.filename'}; + } + $thisfn=$env{'request.filename'}; } if ($thisfn=~m|^/enc/|) { $thisfn=&Apache::lonenc::unencrypted($thisfn); } # is that filename actually a symb? Verify, clean, and return @@ -13573,10 +13347,17 @@ sub symbread { my %bighash; my $syval=''; if (($env{'request.course.fn'}) && ($thisfn)) { + my $targetfn = $thisfn; + if ( ($thisfn =~ m/^(uploaded|editupload)\//) && ($thisfn !~ m/\.(page|sequence)$/) ) { + $targetfn = 'adm/wrapper/'.$thisfn; + } + if ($targetfn =~ m|^adm/wrapper/(ext/.*)|) { + $targetfn=$1; + } unless ($ignoresymbdb) { if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', &GDBM_READER(),0640)) { - $syval=$hash{$thisfn}; + $syval=$hash{$targetfn}; untie(%hash); } if ($syval && $checkforblock) { @@ -13631,7 +13412,7 @@ sub symbread { } } } - } elsif ((!$donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) { + } elsif ((!$donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) { # ------------------------------------------ There is more than one possibility my $realpossible=0; foreach my $id (@possibilities) { @@ -13639,14 +13420,14 @@ sub symbread { my $canaccess; if (($donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) { $canaccess = 1; - } else { + } else { $canaccess = &allowed('bre',$file); } if ($canaccess) { my ($mapid,$resid)=split(/\./,$id); if ($bighash{'map_type_'.$mapid} ne 'page') { my $poss_syval=&encode_symb($bighash{'map_id_'.$mapid}, - $resid,$thisfn); + $resid,$thisfn); next if ($bighash{'randomout_'.$id} && !$env{'request.role.adv'}); next unless (($noenccheck) || ($bighash{'encrypted_'.$id} eq $env{'request.enc'})); if ($checkforblock) { @@ -13827,6 +13608,7 @@ sub rndseed { $which =&get_rand_alg($courseid); } if (defined(&getCODE())) { + if ($which eq '64bit5') { return &rndseed_CODE_64bit5($symb,$courseid,$domain,$username); } elsif ($which eq '64bit4') { @@ -14012,7 +13794,7 @@ sub rndseed_CODE_64bit5 { sub setup_random_from_rndseed { my ($rndseed)=@_; if ($rndseed =~/([,:])/) { - my ($num1,$num2) = map { abs($_); } (split(/[,:]/,$rndseed)); + my ($num1,$num2) = map { abs($_); } (split(/[,:]/,$rndseed)); if ((!$num1) || (!$num2) || ($num1 > 2147483562) || ($num2 > 2147483398)) { &Math::Random::random_set_seed_from_phrase($rndseed); } else { @@ -14196,7 +13978,6 @@ sub repcopy_userfile { } # now the path exists for sure # get a user agent - my $ua=new LWP::UserAgent; my $transferfile=$file.'.in.transfer'; # FIXME: this should flock if (-e $transferfile) { return 'ok'; } @@ -14207,7 +13988,7 @@ sub repcopy_userfile { my $protocol = $protocol{$homeserver}; $protocol = 'http' if ($protocol ne 'https'); $request=new HTTP::Request('GET',$protocol.'://'.$hostname.'/raw/'.$uri); - my $response=$ua->request($request,$transferfile); + my $response = &LONCAPA::LWPReq::makerequest($homeserver,$request,$transferfile,\%perlvar,'',0,1); # did it work? if ($response->is_error()) { unlink($transferfile); @@ -14253,9 +14034,8 @@ sub getuploaded { my $protocol = $protocol{$homeserver}; $protocol = 'http' if ($protocol ne 'https'); $uri = $protocol.'://'.$hostname.'/raw/'.$uri; - my $ua=new LWP::UserAgent; my $request=new HTTP::Request($reqtype,$uri); - my $response=$ua->request($request); + my $response=&LONCAPA::LWPReq::makerequest($homeserver,$request,'',\%perlvar,'',0,1); $$rtncode = $response->code; if (! $response->is_success()) { return 'failed'; @@ -14385,15 +14165,10 @@ sub machine_ids { sub additional_machine_domains { my @domains; - if (-e "$perlvar{'lonTabDir'}/expected_domains.tab") { - if (open(my $fh,"<","$perlvar{'lonTabDir'}/expected_domains.tab")) { - while( my $line = <$fh>) { - chomp($line); - $line =~ s/\s//g; - push(@domains,$line); - } - close($fh); - } + open(my $fh,"<","$perlvar{'lonTabDir'}/expected_domains.tab"); + while( my $line = <$fh>) { + $line =~ s/\s//g; + push(@domains,$line); } return @domains; } @@ -14412,12 +14187,9 @@ sub default_login_domain { } sub shared_institution { - my ($dom,$lonhost) = @_; - if ($lonhost eq '') { - $lonhost = $perlvar{'lonHostID'}; - } + my ($dom) = @_; my $same_intdom; - my $hostintdom = &internet_dom($lonhost); + my $hostintdom = &internet_dom($perlvar{'lonHostID'}); if ($hostintdom ne '') { my %iphost = &get_iphost(); my $primary_id = &domain($dom,'primary'); @@ -14448,10 +14220,9 @@ sub uses_sts { return $sts_on; } } - my $ua=new LWP::UserAgent; my $url = $protocol{$lonhost}.'://'.$hostname.'/index.html'; my $request=new HTTP::Request('HEAD',$url); - my $response=$ua->request($request); + my $response=&LONCAPA::LWPReq::makerequest($lonhost,$request,'',\%perlvar,'','','',1); if ($response->is_success) { my $has_sts = $response->header('Strict-Transport-Security'); if ($has_sts eq '') { @@ -14474,230 +14245,6 @@ sub uses_sts { return; } -sub waf_allssl { - my ($host_name) = @_; - my $alias = &get_proxy_alias(); - if ($host_name eq '') { - $host_name = $ENV{'SERVER_NAME'}; - } - if (($host_name ne '') && ($alias eq $host_name)) { - my $serverhomedom = &host_domain($perlvar{'lonHostID'}); - my %defdomdefaults = &get_domain_defaults($serverhomedom); - if ($defdomdefaults{'waf_sslopt'}) { - return $defdomdefaults{'waf_sslopt'}; - } - } - return; -} - -sub get_requestor_ip { - my ($r,$nolookup,$noproxy) = @_; - my $from_ip; - if (ref($r)) { - if ($r->can('useragent_ip')) { - if ($noproxy && $r->can('client_ip')) { - $from_ip = $r->client_ip(); - } else { - $from_ip = $r->useragent_ip(); - } - } elsif ($r->connection->can('remote_ip')) { - $from_ip = $r->connection->remote_ip(); - } else { - $from_ip = $r->get_remote_host($nolookup); - } - } else { - $from_ip = $ENV{'REMOTE_ADDR'}; - } - return $from_ip if ($noproxy); - # Who controls proxy settings for server - my $dom_in_use = $Apache::lonnet::perlvar{'lonDefDomain'}; - my $proxyinfo = &get_proxy_settings($dom_in_use); - if ((ref($proxyinfo) eq 'HASH') && ($from_ip)) { - if ($proxyinfo->{'vpnint'}) { - if (&ip_match($from_ip,$proxyinfo->{'vpnint'})) { - return $from_ip; - } - } - if ($proxyinfo->{'trusted'}) { - if (&ip_match($from_ip,$proxyinfo->{'trusted'})) { - my $ipheader = $proxyinfo->{'ipheader'}; - my ($ip,$xfor); - if (ref($r)) { - if ($ipheader) { - $ip = $r->headers_in->{$ipheader}; - } - $xfor = $r->headers_in->{'X-Forwarded-For'}; - } else { - if ($ipheader) { - $ip = $ENV{'HTTP_'.uc($ipheader)}; - } - $xfor = $ENV{'HTTP_X_FORWARDED_FOR'}; - } - if (($ip eq '') && ($xfor ne '')) { - foreach my $poss_ip (reverse(split(/\s*,\s*/,$xfor))) { - unless (&ip_match($poss_ip,$proxyinfo->{'trusted'})) { - $ip = $poss_ip; - last; - } - } - } - if ($ip ne '') { - return $ip; - } - } - } - } - return $from_ip; -} - -sub get_proxy_settings { - my ($dom_in_use) = @_; - my %domdefaults = &Apache::lonnet::get_domain_defaults($dom_in_use); - my $proxyinfo = { - ipheader => $domdefaults{'waf_ipheader'}, - trusted => $domdefaults{'waf_trusted'}, - vpnint => $domdefaults{'waf_vpnint'}, - vpnext => $domdefaults{'waf_vpnext'}, - sslopt => $domdefaults{'waf_sslopt'}, - }; - return $proxyinfo; -} - -sub ip_match { - my ($ip,$pattern_str) = @_; - $ip=Net::CIDR::cidrvalidate($ip); - if ($ip) { - return Net::CIDR::cidrlookup($ip,split(/\s*,\s*/,$pattern_str)); - } - return; -} - -sub get_proxy_alias { - my ($lonid) = @_; - if ($lonid eq '') { - $lonid = $perlvar{'lonHostID'}; - } - if (!defined(&hostname($lonid))) { - return; - } - if ($lonid ne '') { - my ($alias,$cached) = &is_cached_new('proxyalias',$lonid); - if ($cached) { - return $alias; - } - my $dom = &Apache::lonnet::host_domain($lonid); - if ($dom ne '') { - my $cachetime = 60*60*24; - my %domconfig = - &Apache::lonnet::get_dom('configuration',['wafproxy'],$dom); - if (ref($domconfig{'wafproxy'}) eq 'HASH') { - if (ref($domconfig{'wafproxy'}{'alias'}) eq 'HASH') { - $alias = $domconfig{'wafproxy'}{'alias'}{$lonid}; - } - } - return &do_cache_new('proxyalias',$lonid,$alias,$cachetime); - } - } - return; -} - -sub use_proxy_alias { - my ($r,$lonid) = @_; - my $alias = &get_proxy_alias($lonid); - if ($alias) { - my $dom = &host_domain($lonid); - if ($dom ne '') { - my $proxyinfo = &get_proxy_settings($dom); - my ($vpnint,$remote_ip); - if (ref($proxyinfo) eq 'HASH') { - $vpnint = $proxyinfo->{'vpnint'}; - if ($vpnint) { - $remote_ip = &get_requestor_ip($r,1,1); - } - } - unless ($vpnint && &ip_match($remote_ip,$vpnint)) { - return $alias; - } - } - } - return; -} - -sub alias_sso { - my ($lonid) = @_; - if ($lonid eq '') { - $lonid = $perlvar{'lonHostID'}; - } - if (!defined(&hostname($lonid))) { - return; - } - if ($lonid ne '') { - my ($use_alias,$cached) = &is_cached_new('proxysaml',$lonid); - if ($cached) { - return $use_alias; - } - my $dom = &Apache::lonnet::host_domain($lonid); - if ($dom ne '') { - my $cachetime = 60*60*24; - my %domconfig = - &Apache::lonnet::get_dom('configuration',['wafproxy'],$dom); - if (ref($domconfig{'wafproxy'}) eq 'HASH') { - if (ref($domconfig{'wafproxy'}{'saml'}) eq 'HASH') { - $use_alias = $domconfig{'wafproxy'}{'saml'}{$lonid}; - } - } - return &do_cache_new('proxysaml',$lonid,$use_alias,$cachetime); - } - } - return; -} - -sub get_saml_landing { - my ($lonid) = @_; - if ($lonid eq '') { - my $defdom = &default_login_domain(); - my @hosts = ¤t_machine_ids(); - if (@hosts > 1) { - foreach my $hostid (@hosts) { - if (&host_domain($hostid) eq $defdom) { - $lonid = $hostid; - last; - } - } - } else { - $lonid = $perlvar{'lonHostID'}; - } - if ($lonid) { - unless (&Apache::lonnet::host_domain($lonid) eq $defdom) { - return; - } - } else { - return; - } - } elsif (!defined(&hostname($lonid))) { - return; - } - my ($landing,$cached) = &is_cached_new('samllanding',$lonid); - if ($cached) { - return $landing; - } - my $dom = &Apache::lonnet::host_domain($lonid); - if ($dom ne '') { - my $cachetime = 60*60*24; - my %domconfig = - &Apache::lonnet::get_dom('configuration',['login'],$dom); - if (ref($domconfig{'login'}) eq 'HASH') { - if (ref($domconfig{'login'}{'saml'}) eq 'HASH') { - if (ref($domconfig{'login'}{'saml'}{$lonid}) eq 'HASH') { - $landing = 1; - } - } - } - return &do_cache_new('samllanding',$lonid,$landing,$cachetime); - } - return; -} - # ------------------------------------------------------------- Declutters URLs sub declutter { @@ -14837,36 +14384,36 @@ sub get_dns { } while (%alldns) { my ($dns) = sort { $b cmp $a } keys(%alldns); - my @content; - if ($dns eq Sys::Hostname::FQDN::fqdn()) { - my $command = (split('/',$url))[3]; - my ($dir,$file) = &parse_getdns_url($command,$url); - delete($alldns{$dns}); - next if (($dir eq '') || ($file eq '')); - if (open(my $config,'<',"$dir/$file")) { - @content = <$config>; - close($config); - } - } else { - my $ua=new LWP::UserAgent; - $ua->timeout(30); - my $request=new HTTP::Request('GET',"$alldns{$dns}://$dns$url"); - my $response=$ua->request($request); - delete($alldns{$dns}); - next if ($response->is_error()); - @content = split("\n",$response->content); - } - unless ($nocache) { - &do_cache_new('dns',$url,\@content,30*24*60*60); + my $request=new HTTP::Request('GET',"$alldns{$dns}://$dns$url"); + my $response = &LONCAPA::LWPReq::makerequest('',$request,'',\%perlvar,30,0); + delete($alldns{$dns}); + next if ($response->is_error()); + if ($url eq '/adm/dns/loncapaCRL') { + return &$func($response); + } else { + my @content = split("\n",$response->content); + unless ($nocache) { + &do_cache_new('dns',$url,\@content,30*24*60*60); + } + &$func(\@content,$hashref); + return; } - &$func(\@content,$hashref); - return; } - my $which = (split('/',$url))[3]; - &logthis("unable to contact DNS defaulting to on disk file dns_$which.tab\n"); - if (open(my $config,"<","$perlvar{'lonTabDir'}/dns_$which.tab")) { - my @content = <$config>; - &$func(\@content,$hashref); + my $which = (split('/',$url,4))[3]; + if ($which eq 'loncapaCRL') { + my $diskfile = "$perlvar{'lonCertificateDirectory'}/$perlvar{'lonnetCertRevocationList'}"; + if (-e $diskfile) { + &logthis("unable to contact DNS, on disk file $diskfile not updated"); + } else { + &logthis("unable to contact DNS, no on disk file $diskfile available"); + } + } else { + &logthis("unable to contact DNS defaulting to on disk file dns_$which.tab\n"); + if (open(my $config,"<","$perlvar{'lonTabDir'}/dns_$which.tab")) { + my @content = <$config>; + close($config); + &$func(\@content,$hashref); + } } return; } @@ -14895,7 +14442,7 @@ sub parse_dns_checksums_tab { if (ref($lines) eq 'ARRAY') { chomp(@{$lines}); my $version = shift(@{$lines}); - if ($version eq $release) { + if ($version eq $release) { foreach my $line (@{$lines}) { my ($file,$version,$shasum) = split(/,/,$line); if ($file =~ m{^/etc/httpd/conf}) { @@ -14927,19 +14474,77 @@ sub fetch_dns_checksums { return \%checksums; } -sub parse_getdns_url { - my ($command,$url) = @_; - my $dir = $perlvar{'lonTabDir'}; - my $file; - if ($command eq 'hosts') { - $file = 'dns_hosts.tab'; - } elsif ($command eq 'domain') { - $file = 'dns_domain.tab'; - } elsif ($command eq 'checksums') { - my $version = (split('/',$url))[4]; - $file = "dns_checksums/$version.tab", +sub fetch_crl_pemfile { + return &get_dns("/adm/dns/loncapaCRL",\&save_crl_pem,1,1); +} + +sub save_crl_pem { + my ($response) = @_; + my ($msg,$hadchanges); + if (ref($response)) { + my $now = time; + my $lonca = $perlvar{'lonCertificateDirectory'}.'/'.$perlvar{'lonnetCertificateAuthority'}; + my $tmpcrl = $tmpdir.'/'.$perlvar{'lonnetCertRevocationList'}.'_'.$now.'.'.$$.'.tmp'; + if (open(my $fh,'>',"$tmpcrl")) { + print $fh $response->content; + close($fh); + if (-e $lonca) { + if (open(PIPE,"openssl crl -in $tmpcrl -inform pem -CAfile $lonca -noout 2>&1 |")) { + my $check = ; + close(PIPE); + chomp($check); + if ($check eq 'verify OK') { + my $dest = "$perlvar{'lonCertificateDirectory'}/$perlvar{'lonnetCertRevocationList'}"; + my $backup; + if (-e $dest) { + if (&File::Copy::move($dest,"$dest.bak")) { + $backup = 'ok'; + } + } + if (&File::Copy::move($tmpcrl,$dest)) { + $msg = 'ok'; + if ($backup) { + my (%oldnums,%newnums); + if (open(PIPE, "openssl crl -inform PEM -text -noout -in $dest.bak |grep 'Serial Number' |")) { + while () { + $oldnums{(split(/:/))[1]} = 1; + } + close(PIPE); + } + if (open(PIPE, "openssl crl -inform PEM -text -noout -in $dest |grep 'Serial Number' |")) { + while() { + $newnums{(split(/:/))[1]} = 1; + } + close(PIPE); + } + foreach my $key (sort {$b <=> $a } (keys(%newnums))) { + unless (exists($oldnums{$key})) { + $hadchanges = 1; + last; + } + } + unless ($hadchanges) { + foreach my $key (sort {$b <=> $a } (keys(%oldnums))) { + unless (exists($newnums{$key})) { + $hadchanges = 1; + last; + } + } + } + } + } + } else { + unlink($tmpcrl); + } + } else { + unlink($tmpcrl); + } + } else { + unlink($tmpcrl); + } + } } - return ($dir,$file); + return ($msg,$hadchanges); } # ------------------------------------------------------------ Read domain file @@ -15064,6 +14669,7 @@ sub parse_getdns_url { &purge_remembered(); &reset_domain_info(); &reset_hosts_ip_info(); + undef(%internetdom); undef(%name_to_host); undef(%hostname); undef(%hostdom); @@ -15106,6 +14712,11 @@ sub parse_getdns_url { return %hostdom; } + sub all_host_intdom { + &load_hosts_tab() if (!$loaded); + return %internetdom; + } + sub is_library { &load_hosts_tab() if (!$loaded); @@ -15336,9 +14947,9 @@ sub all_loncaparevs { return qw(1.1 1.2 1.3 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11); } -# ------------------------------------------------------- Read loncaparev table +# ---------------------------------------------------------- Read loncaparev table { - sub load_loncaparevs { + sub load_loncaparevs { if (-e "$perlvar{'lonTabDir'}/loncaparevs.tab") { if (open(my $config,"<","$perlvar{'lonTabDir'}/loncaparevs.tab")) { while (my $configline=<$config>) { @@ -15352,7 +14963,7 @@ sub all_loncaparevs { } } -# ----------------------------------------------------- Read serverhostID table +# ---------------------------------------------------------- Read serverhostID table { sub load_serverhomeIDs { if (-e "$perlvar{'lonTabDir'}/serverhomeIDs.tab") { @@ -15444,11 +15055,11 @@ BEGIN { close($config); } -# --------------------------------------------------------- Read loncaparev table +# ---------------------------------------------------------- Read loncaparev table &load_loncaparevs(); -# ------------------------------------------------------- Read serverhostID table +# ---------------------------------------------------------- Read serverhostID table &load_serverhomeIDs(); @@ -15462,7 +15073,15 @@ BEGIN { my $item = $token->[1]; my $name = $token->[2]{'name'}; my $value = $token->[2]{'value'}; - if ($item ne '' && $name ne '' && $value ne '') { + my $valuematch = $token->[2]{'valuematch'}; + my $namematch = $token->[2]{'namematch'}; + if ($item eq 'parameter') { + if (($namematch ne '') || (($name ne '') && ($value ne '' || $valuematch ne ''))) { + my $release = $parser->get_text(); + $release =~ s/(^\s*|\s*$ )//gx; + $needsrelease{$item.':'.$name.':'.$value.':'.$valuematch.':'.$namematch} = $release; + } + } elsif ($item ne '' && $name ne '') { my $release = $parser->get_text(); $release =~ s/(^\s*|\s*$ )//gx; $needsrelease{$item.':'.$name.':'.$value} = $release; @@ -15745,10 +15364,12 @@ the answer, and also caches if there is =item * X -B: find the usernames behind a list of IDs -(IDs are a unique resource in a domain, there must be only 1 ID per -username, and only 1 username per ID in a specific domain) (returns -hash: id=>name,id=>name) +B: find the usernames behind either +a list of student/employee IDs or clicker IDs +(student/employee IDs are a unique resource in a domain, there must be +only 1 ID per username, and only 1 username per ID in a specific domain). +clickerIDs are not necessarily unique, as students might share clickers. +(returns hash: id=>name,id=>name) =item * X @@ -15757,7 +15378,27 @@ usernames (returns hash: name=>id,name=> =item * X -B: store away a list of names and associated IDs +B: store away a list of +names and associated student/employee IDs or clicker IDs. + +=item * +X +B: delete unwanted +student/employee ID or clicker ID username look-ups from domain. +The homeserver ($uhome) and namespace ($namespace) are optional. +If no $uhome is provided, it will be determined usig &homeserver() +for each user. If no $namespace is provided, the default is ids. + +=item * +X +B: update +clicker ID-to-username look-ups in clickers.db on library server. +Permitted actions are add or del (i.e., add or delete). The +clickers.db contains clickerID as keys (escaped), and each corresponding +value is an escaped comma-separated list of usernames (for whom the +library server is the homeserver), who registered that particular ID. +If $critical is true, the update will be sent via &critical, otherwise +&reply() will be used. =item * X @@ -15805,13 +15446,13 @@ The first argument is required, all othe $priv is the privilege being checked. $uri contains additional information about what is being checked for access (e.g., -URL, course ID etc.). +URL, course ID etc.). $symb is the unique resource instance identifier in a course; if needed, -but not provided, it will be retrieved via a call to &symbread(). -$role is the role for which a priv is being checked (only used if priv is evb). -$clientip is the user's IP address (only used when checking for access to portfolio +but not provided, it will be retrieved via a call to &symbread(). +$role is the role for which a priv is being checked (only used if priv is evb). +$clientip is the user's IP address (only used when checking for access to portfolio files). -$noblockcheck, if true, skips calls to &has_comm_blocking() for the bre priv. This +$noblockcheck, if true, skips calls to &has_comm_blocking() for the bre priv. This prevents recursive calls to &allowed. F: full access @@ -15821,7 +15462,7 @@ prevents recursive calls to &allowed. 2: browse allowed A: passphrase authentication needed B: access temporarily blocked because of a blocking event in a course. - D: access blocked because access is required via session initiated via deep-link + D: access blocked because access is required via session initiated via deep-link =item * @@ -15874,9 +15515,9 @@ provided for types, will default to retu =item * in_course($udom,$uname,$cdom,$cnum,$type,$hideprivileged) : determine if -user: $uname:$udom has a role in the course: $cdom_$cnum. +user: $uname:$udom has a role in the course: $cdom_$cnum. -Additional optional arguments are: $type (if role checking is to be restricted +Additional optional arguments are: $type (if role checking is to be restricted to certain user status types -- previous (expired roles), active (currently available roles) or future (roles available in the future), and $hideprivileged -- if true will not report course roles for users who @@ -16114,6 +15755,10 @@ data base, returning a hash that is keye values that are the resource value. I believe that the timestamps and versions are also returned. +get_numsuppfiles($cnum,$cdom) : retrieve number of files in a course's +supplemental content area. This routine caches the number of files for +10 minutes. + =back =head2 Course Modification @@ -16284,13 +15929,15 @@ condval($condidx) : value of condition i metadata($uri,$what,$toolsymb,$liburi,$prefix,$depthcount) : request a resource's metadata, $what should be either a specific key, or either 'keys' (to get a list of possible keys) or 'packages' to get a list of -packages that this resource currently uses, the last 3 arguments are +packages that this resource currently uses, the last 3 arguments are only used internally for recursive metadata. the toolsymb is only used where the uri is for an external tool (for which the uri as well as the symb are guaranteed to be unique). -this function automatically caches all requests +this function automatically caches all requests except any made recursively +to retrieve a list of metadata keys for an imported library file ($liburi is +defined). =item * @@ -16300,20 +15947,20 @@ will be stored for query =item * -symbread($filename,$donotrecurse,$ignorecachednull,$checkforblock,$possibles) : -return symbolic list entry (all arguments optional). +symbread($filename,$donotrecurse,$ignorecachednull,$checkforblock,$possibles) : +return symbolic list entry (all arguments optional). -Args: filename is the filename (including path) for the file for which a symb -is required; donotrecurse, if true will prevent calls to allowed() being made -to check access status if more than one resource was found in the bighash -(see rev. 1.249) to avoid an infinite loop if an ambiguous resource is part of -a randompick); ignorecachednull, if true will prevent a symb of '' being +Args: filename is the filename (including path) for the file for which a symb +is required; donotrecurse, if true will prevent calls to allowed() being made +to check access status if more than one resource was found in the bighash +(see rev. 1.249) to avoid an infinite loop if an ambiguous resource is part of +a randompick); ignorecachednull, if true will prevent a symb of '' being returned if $env{$cache_str} is defined as ''; checkforblock if true will cause possible symbs to be checked to determine if they are subject to content blocking, if so they will not be included as possible symbs; possibles is a -ref to a hash, which, as a side effect, will be populated with all possible +ref to a hash, which, as a side effect, will be populated with all possible symbs (content blocking not tested). - + returns the data handle =item * @@ -16323,9 +15970,9 @@ and is a possible symb for the URL in $t resource that the user accessed using /enc/ returns a 1 on success, 0 on failure, user must be in a course, as it assumes the existence of the course initial hash, and uses $env('request.course.id'}. The third -arg is an optional reference to a scalar. If this arg is passed in the +arg is an optional reference to a scalar. If this arg is passed in the call to symbverify, it will be set to 1 if the symb has been set to be -encrypted; otherwise it will be null. +encrypted; otherwise it will be null. =item * @@ -16378,13 +16025,13 @@ expirespread($uname,$udom,$stype,$usymb) devalidate($symb) : devalidate temporary spreadsheet calculations, forcing spreadsheet to reevaluate the resource scores next time. -=item * +=item * can_edit_resource($file,$cnum,$cdom,$resurl,$symb,$group) : determine if current user can edit a particular resource, when viewing in course context. input: six args -- filename (decluttered), course number, course domain, - url, symb (if registered) and group (if this is a + url, symb (if registered) and group (if this is a group item -- e.g., bulletin board, group page etc.). output: array of five scalars -- @@ -16392,15 +16039,15 @@ when viewing in course context. $home -- homeserver of resource (i.e., for author if published, or course if uploaded.). $switchserver -- 1 if server switch will be needed. - $forceedit -- 1 if icon/link should be to go to edit mode + $forceedit -- 1 if icon/link should be to go to edit mode $forceview -- 1 if icon/link should be to go to view mode =item * is_course_upload($file,$cnum,$cdom) -Used in course context to determine if current file was uploaded to -the course (i.e., would be found in /userfiles/docs on the course's +Used in course context to determine if current file was uploaded to +the course (i.e., would be found in /userfiles/docs on the course's homeserver. input: 3 args -- filename (decluttered), course number and course domain. @@ -16414,20 +16061,20 @@ homeserver. =item * -store($storehash,$symb,$namespace,$udom,$uname,$laststore) : stores hash +store($storehash,$symb,$namespace,$udom,$uname,$laststore) : stores hash permanently for this url; hashref needs to be given and should be a \%hashname; the remaining args aren't required and if they aren't passed or are '' they will -be derived from the env (with the exception of $laststore, which is an +be derived from the env (with the exception of $laststore, which is an optional arg used when a user's submission is stored in grading). $laststore is $version=$timestamp, where $version is the most recent version number retrieved for the corresponding $symb in the $namespace db file, and $timestamp is the timestamp for that transaction (UNIX time). -$laststore is currently only passed when cstore() is called by +$laststore is currently only passed when cstore() is called by structuretags::finalize_storage(). =item * -cstore($storehash,$symb,$namespace,$udom,$uname,$laststore) : same as store +cstore($storehash,$symb,$namespace,$udom,$uname,$laststore) : same as store but uses critical subroutine =item * @@ -16565,7 +16212,7 @@ server ($udom and $uhome are optional) =item * -get_domain_defaults($target_domain,$ignore_cache) : returns hash with defaults +get_domain_defaults($target_domain,$ignore_cache) : returns hash with defaults for: authentication, language, quotas, timezone, date locale, and portal URL in the target domain. @@ -16599,7 +16246,7 @@ requestcourses: ability to request cours =over =item -official, unofficial, community, textbook +official, unofficial, community, textbook, placement =back @@ -16620,8 +16267,8 @@ for course's uploaded content. =over =item -canuse_pdfforms, officialcredits, unofficialcredits, textbookcredits, officialquota, unofficialquota, -communityquota, textbookquota +canuse_pdfforms, officialcredits, unofficialcredits, textbookcredits, officialquota, unofficialquota, +communityquota, textbookquota, placementquota =back @@ -16631,7 +16278,7 @@ on your servers. =over -=item +=item remotesessions, hostedsessions =back @@ -16639,10 +16286,10 @@ remotesessions, hostedsessions =back In cases where a domain coordinator has never used the "Set Domain Configuration" -utility to create a configuration.db file on a domain's primary library server +utility to create a configuration.db file on a domain's primary library server only the following domain defaults: auth_def, auth_arg_def, lang_def -- corresponding values are authentication type (internal, krb4, krb5, -or localauth), initial password or a kerberos realm, language (e.g., en-us) -- +or localauth), initial password or a kerberos realm, language (e.g., en-us) -- will be available. Values are retrieved from cache (if current), unless the optional $ignore_cache arg is true, or from domain's configuration.db (if available), or lastly from values in lonTabs/dns_domain,tab, or lonTabs/domain.tab. @@ -17071,8 +16718,8 @@ Returns: get_timebased_id(): -Attempts to get a unique timestamp-based suffix for use with items added to a -course via the Course Editor (e.g., folders, composite pages, +Attempts to get a unique timestamp-based suffix for use with items added to a +course via the Course Editor (e.g., folders, composite pages, group bulletin boards). Args: (first three required; six others optional) @@ -17083,24 +16730,24 @@ Args: (first three required; six others 2. keyid (alphanumeric): name of temporary locking key in hash, e.g., num, boardids -3. namespace: name of gdbm file used to store suffixes already assigned; +3. namespace: name of gdbm file used to store suffixes already assigned; file will be named nohist_namespace.db 4. cdom: domain of course; default is current course domain from %env 5. cnum: course number; default is current course number from %env -6. idtype: set to concat if an additional digit is to be appended to the +6. idtype: set to concat if an additional digit is to be appended to the unix timestamp to form the suffix, if the plain timestamp is already - in use. Default is to not do this, but simply increment the unix + in use. Default is to not do this, but simply increment the unix timestamp by 1 until a unique key is obtained. 7. who: holder of locking key; defaults to user:domain for user. -8. locktries: number of attempts to obtain a lock (sleep of 1s before +8. locktries: number of attempts to obtain a lock (sleep of 1s before retrying); default is 3. -9. maxtries: number of attempts to obtain a unique suffix; default is 20. +9. maxtries: number of attempts to obtain a unique suffix; default is 20. Returns: