--- loncom/lonnet/perl/lonnet.pm 2014/04/16 16:21:24 1.1172.2.43 +++ loncom/lonnet/perl/lonnet.pm 2015/03/11 04:21:21 1.1172.2.60 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1172.2.43 2014/04/16 16:21:24 raeburn Exp $ +# $Id: lonnet.pm,v 1.1172.2.60 2015/03/11 04:21:21 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -956,13 +956,30 @@ sub has_user_session { # --------- determine least loaded server in a user's domain which allows login sub choose_server { - my ($udom,$checkloginvia,$required) = @_; + my ($udom,$checkloginvia,$required,$skiploadbal) = @_; my %domconfhash = &Apache::loncommon::get_domainconf($udom); my %servers = &get_servers($udom); my $lowest_load = 30000; - my ($login_host,$hostname,$portal_path,$isredirect); + my ($login_host,$hostname,$portal_path,$isredirect,$balancers); + if ($skiploadbal) { + ($balancers,my $cached)=&is_cached_new('loadbalancing',$udom); + unless (defined($cached)) { + my $cachetime = 60*60*24; + my %domconfig = + &Apache::lonnet::get_dom('configuration',['loadbalancing'],$udom); + if (ref($domconfig{'loadbalancing'}) eq 'HASH') { + $balancers = &do_cache_new('loadbalancing',$udom,$domconfig{'loadbalancing'}, + $cachetime); + } + } + } foreach my $lonhost (keys(%servers)) { my $loginvia; + if ($skiploadbal) { + if (ref($balancers) eq 'HASH') { + next if (exists($balancers->{$lonhost})); + } + } if ($checkloginvia) { $loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost}; if ($loginvia) { @@ -1630,6 +1647,7 @@ sub dump_dom { sub get_dom { my ($namespace,$storearr,$udom,$uhome)=@_; + return if ($udom eq 'public'); my $items=''; foreach my $item (@$storearr) { $items.=&escape($item).'&'; @@ -1637,6 +1655,7 @@ sub get_dom { $items=~s/\&$//; if (!$udom) { $udom=$env{'user.domain'}; + return if ($udom eq 'public'); if (defined(&domain($udom,'primary'))) { $uhome=&domain($udom,'primary'); } else { @@ -1740,14 +1759,13 @@ sub retrieve_inst_usertypes { my %domdefs = &Apache::lonnet::get_domain_defaults($udom); if ((ref($domdefs{'inststatustypes'}) eq 'HASH') && (ref($domdefs{'inststatusorder'}) eq 'ARRAY')) { - %returnhash = %{$domdefs{'inststatustypes'}}; - @order = @{$domdefs{'inststatusorder'}}; + return ($domdefs{'inststatustypes'},$domdefs{'inststatusorder'}); } else { if (defined(&domain($udom,'primary'))) { my $uhome=&domain($udom,'primary'); my $rep=&reply("inst_usertypes:$udom",$uhome); if ($rep =~ /^(con_lost|error|no_such_host|refused)/) { - &logthis("get_dom failed - $rep returned from $uhome in domain: $udom"); + &logthis("retrieve_inst_usertypes failed - $rep returned from $uhome in domain: $udom"); return (\%returnhash,\@order); } my ($hashitems,$orderitems) = split(/:/,$rep); @@ -1763,10 +1781,10 @@ sub retrieve_inst_usertypes { push(@order,&unescape($item)); } } else { - &logthis("get_dom failed - no primary domain server for $udom"); + &logthis("retrieve_inst_usertypes failed - no primary domain server for $udom"); } + return (\%returnhash,\@order); } - return (\%returnhash,\@order); } sub is_domainimage { @@ -2007,7 +2025,8 @@ sub get_domain_defaults { &Apache::lonnet::get_dom('configuration',['defaults','quotas', 'requestcourses','inststatus', 'coursedefaults','usersessions', - 'requestauthor','selfenrollment'],$domain); + 'requestauthor','selfenrollment', + 'coursecategories'],$domain); my @coursetypes = ('official','unofficial','community','textbook'); if (ref($domconfig{'defaults'}) eq 'HASH') { $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'}; @@ -2046,11 +2065,16 @@ sub get_domain_defaults { $domdefaults{'requestauthor'} = $domconfig{'requestauthor'}; } if (ref($domconfig{'inststatus'}) eq 'HASH') { - foreach my $item ('inststatustypes','inststatusorder') { + foreach my $item ('inststatustypes','inststatusorder','inststatusguest') { $domdefaults{$item} = $domconfig{'inststatus'}{$item}; } } if (ref($domconfig{'coursedefaults'}) eq 'HASH') { + $domdefaults{'usejsme'} = $domconfig{'coursedefaults'}{'usejsme'}; + $domdefaults{'uselcmath'} = $domconfig{'coursedefaults'}{'uselcmath'}; + if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') { + $domdefaults{'postsubmit'} = $domconfig{'coursedefaults'}{'postsubmit'}{'client'}; + } foreach my $type (@coursetypes) { if (ref($domconfig{'coursedefaults'}{'coursecredits'}) eq 'HASH') { unless ($type eq 'community') { @@ -2060,6 +2084,12 @@ sub get_domain_defaults { if (ref($domconfig{'coursedefaults'}{'uploadquota'}) eq 'HASH') { $domdefaults{$type.'quota'} = $domconfig{'coursedefaults'}{'uploadquota'}{$type}; } + if ($domdefaults{'postsubmit'} eq 'on') { + if (ref($domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') { + $domdefaults{$type.'postsubtimeout'} = + $domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}{$type}; + } + } } } if (ref($domconfig{'usersessions'}) eq 'HASH') { @@ -2098,6 +2128,16 @@ sub get_domain_defaults { } } } + if (ref($domconfig{'coursecategories'}) eq 'HASH') { + $domdefaults{'catauth'} = 'std'; + $domdefaults{'catunauth'} = 'std'; + if ($domconfig{'coursecategories'}{'auth'}) { + $domdefaults{'catauth'} = $domconfig{'coursecategories'}{'auth'}; + } + if ($domconfig{'coursecategories'}{'unauth'}) { + $domdefaults{'catunauth'} = $domconfig{'coursecategories'}{'unauth'}; + } + } &do_cache_new('domdefaults',$domain,\%domdefaults,$cachetime); return %domdefaults; } @@ -2688,7 +2728,12 @@ sub ssi { &Apache::lonenc::check_encrypt(\$fn); if (%form) { $request=new HTTP::Request('POST',&absolute_url().$fn); - $request->content(join('&',map { &escape($_).'='.&escape($form{$_}) } keys(%form))); + $request->content(join('&',map { + my $name = escape($_); + "$name=" . ( ref($form{$_}) eq 'ARRAY' + ? join("&$name=", map {escape($_) } @{$form{$_}}) + : &escape($form{$_}) ); + } keys(%form))); } else { $request=new HTTP::Request('GET',&absolute_url().$fn); } @@ -5148,7 +5193,7 @@ sub privileged { my %rolesdump = &dump("roles", $domain, $username) or return 0; my $now = time; - for my $role (@rolesdump{grep { ! /^rolesdef_/ } keys %rolesdump}) { + 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) @@ -5237,7 +5282,7 @@ sub rolesinit { my %allroles=(); my %allgroups=(); - for my $area (grep { ! /^rolesdef_/ } keys %rolesdump) { + for my $area (grep { ! /^rolesdef_/ } keys(%rolesdump)) { my $role = $rolesdump{$area}; $area =~ s/\_\w\w$//; @@ -5677,18 +5722,17 @@ sub dump { if (!$uname) { $uname=$env{'user.name'}; } my $uhome=&homeserver($uname,$udomain); - my $reply; + if ($regexp) { + $regexp=&escape($regexp); + } else { + $regexp='.'; + } if (grep { $_ eq $uhome } ¤t_machine_ids()) { # user is hosted on this machine - $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)}; } - if ($regexp) { - $regexp=&escape($regexp); - } else { - $regexp='.'; - } my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome); my @pairs=split(/\&/,$rep); my %returnhash=(); @@ -5736,7 +5780,15 @@ sub currentdump { $sdom = $env{'user.domain'} if (! defined($sdom)); $sname = $env{'user.name'} if (! defined($sname)); my $uhome = &homeserver($sname,$sdom); - my $rep=reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome); + my $rep; + + if (grep { $_ eq $uhome } current_machine_ids()) { + $rep = LONCAPA::Lond::dump_profile_database(join(":", ($sdom, $sname, + $courseid))); + } else { + $rep = reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome); + } + return if ($rep =~ /^(error:|no_such_host)/); # my %returnhash=(); @@ -5857,7 +5909,7 @@ sub newput { # --------------------------------------------------------- putstore interface sub putstore { - my ($namespace,$symb,$version,$storehash,$udomain,$uname)=@_; + my ($namespace,$symb,$version,$storehash,$udomain,$uname,$tolog)=@_; if (!$udomain) { $udomain=$env{'user.domain'}; } if (!$uname) { $uname=$env{'user.name'}; } my $uhome=&homeserver($uname,$udomain); @@ -5871,6 +5923,17 @@ sub putstore { my $reply = &reply("putstore:$udomain:$uname:$namespace:$esc_symb:$esc_v:$items", $uhome); + if (($tolog) && ($reply eq 'ok')) { + my $namevalue=''; + foreach my $key (keys(%{$storehash})) { + $namevalue.=&escape($key).'='.&freeze_escape($storehash->{$key}).'&'; + } + $namevalue .= 'ip='.&escape($ENV{'REMOTE_ADDR'}). + '&host='.&escape($perlvar{'lonHostID'}). + '&version='.$esc_v. + '&by='.&escape($env{'user.name'}.':'.$env{'user.domain'}); + &Apache::lonnet::courselog($symb.':'.$uname.':'.$udomain.':PUTSTORE:'.$namevalue); + } if ($reply eq 'unknown_cmd') { # gfall back to way things use to be done return &old_putstore($namespace,$symb,$version,$storehash,$udomain, @@ -6029,10 +6092,15 @@ sub get_timebased_id { my %inuse = &Apache::lonnet::dump('nohist_'.$namespace,$cdom,$cnum,$prefix); my $id = time; $newid = $id; + if ($idtype eq 'addcode') { + $newid .= &sixnum_code(); + } my $idtries = 0; while (exists($inuse{$prefix."\0".$newid}) && $idtries < $maxtries) { if ($idtype eq 'concat') { $newid = $id.$idtries; + } elsif ($idtype eq 'addcode') { + $newid = $newid.&sixnum_code(); } else { $newid ++; } @@ -6049,6 +6117,7 @@ sub get_timebased_id { $error = 'error saving new item: '.$putresult; } } else { + undef($newid); $error = ('error: no unique suffix available for the new item '); } # remove lock @@ -6057,10 +6126,21 @@ sub get_timebased_id { } else { $error = "error: could not obtain lockfile\n"; $dellock = 'ok'; + if (($prefix eq 'paste') && ($namespace eq 'courseeditor') && ($keyid eq 'num')) { + $dellock = 'nolock'; + } } return ($newid,$dellock,$error); } +sub sixnum_code { + my $code; + for (0..6) { + $code .= int( rand(9) ); + } + return $code; +} + # -------------------------------------------------- portfolio access checking sub portfolio_access { @@ -7961,7 +8041,7 @@ sub auto_validate_class_sec { sub auto_crsreq_update { my ($cdom,$cnum,$crstype,$action,$ownername,$ownerdomain,$fullname,$title, - $code,$inbound) = @_; + $code,$accessstart,$accessend,$inbound) = @_; my ($homeserver,%crsreqresponse); if ($cdom =~ /^$match_domain$/) { $homeserver = &domain($cdom,'primary'); @@ -7974,7 +8054,8 @@ sub auto_crsreq_update { my $response=&reply('autocrsrequpdate:'.$cdom.':'.$cnum.':'.&escape($crstype). ':'.&escape($action).':'.&escape($ownername).':'. &escape($ownerdomain).':'.&escape($fullname).':'. - &escape($title).':'.&escape($code).':'.$info,$homeserver); + &escape($title).':'.&escape($code).':'. + &escape($accessstart).':'.&escape($accessend).':'.$info,$homeserver); unless ($response =~ /(con_lost|error|no_such_host|refused)/) { my @items = split(/&/,$response); foreach my $item (@items) { @@ -10261,7 +10342,7 @@ sub metadata { ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ m{^/*uploaded/.+\.sequence$})) { return undef; } - if (($uri =~ /^priv/ || $uri=~/home\/httpd\/html\/priv/) + if (($uri =~ /^priv/ || $uri=~m{^home/httpd/html/priv}) && &Apache::lonxml::get_state('target') =~ /^(|meta)$/) { return undef; } @@ -10522,7 +10603,7 @@ sub metadata { $metaentry{':keys'} = join(',',keys(%metathesekeys)); &metadata_generate_part0(\%metathesekeys,\%metaentry,$uri); - $metaentry{':allpossiblekeys'}=join(',',keys %metathesekeys); + $metaentry{':allpossiblekeys'}=join(',',keys(%metathesekeys)); &do_cache_new('meta',$uri,\%metaentry,$cachetime); # this is the end of "was not already recently cached } @@ -10894,14 +10975,10 @@ sub deversion { sub symbread { my ($thisfn,$donotrecurse)=@_; - my $cache_str; - if ($thisfn ne '') { - $cache_str='request.symbread.cached.'.$thisfn; - if ($env{$cache_str} ne '') { - return $env{$cache_str}; - } - } else { + my $cache_str='request.symbread.cached.'.$thisfn; + if (defined($env{$cache_str})) { return $env{$cache_str}; } # no filename provided? try from environment + unless ($thisfn) { if ($env{'request.symb'}) { return $env{$cache_str}=&symbclean($env{'request.symb'}); } @@ -11318,8 +11395,12 @@ sub rndseed_CODE_64bit5 { sub setup_random_from_rndseed { my ($rndseed)=@_; if ($rndseed =~/([,:])/) { - my ($num1,$num2)=split(/[,:]/,$rndseed); - &Math::Random::random_set_seed(abs($num1),abs($num2)); + my ($num1,$num2) = map { abs($_); } (split(/[,:]/,$rndseed)); + if ((!$num1) || (!$num2) || ($num1 > 2147483562) || ($num2 > 2147483398)) { + &Math::Random::random_set_seed_from_phrase($rndseed); + } else { + &Math::Random::random_set_seed($num1,$num2); + } } else { &Math::Random::random_set_seed_from_phrase($rndseed); } @@ -11710,7 +11791,9 @@ sub default_login_domain { sub declutter { my $thisfn=shift; if ($thisfn=~m|^/enc/|) { $thisfn=&Apache::lonenc::unencrypted($thisfn); } - $thisfn=~s/^\Q$perlvar{'lonDocRoot'}\E//; + unless ($thisfn=~m{^/home/httpd/html/priv/}) { + $thisfn=~s{^/home/httpd/html}{}; + } $thisfn=~s/^\///; $thisfn=~s|^adm/wrapper/||; $thisfn=~s|^adm/coursedocs/showdoc/||; @@ -11837,7 +11920,7 @@ sub get_dns { $alldns{$host} = $protocol; } while (%alldns) { - my ($dns) = keys(%alldns); + my ($dns) = sort { $b cmp $a } keys(%alldns); my $ua=new LWP::UserAgent; $ua->timeout(30); my $request=new HTTP::Request('GET',"$alldns{$dns}://$dns$url"); @@ -11863,8 +11946,22 @@ sub get_dns { # ------------------------------------------------------Get DNS checksums file sub parse_dns_checksums_tab { my ($lines,$hashref) = @_; - my $machine_dom = &Apache::lonnet::host_domain($perlvar{'lonHostID'}); + my $lonhost = $perlvar{'lonHostID'}; + my $machine_dom = &Apache::lonnet::host_domain($lonhost); my $loncaparev = &get_server_loncaparev($machine_dom); + my $distro = (split(/\:/,&get_server_distarch($lonhost)))[0]; + my $webconfdir = '/etc/httpd/conf'; + if ($distro =~ /^(ubuntu|debian)(\d+)$/) { + $webconfdir = '/etc/apache2'; + } elsif ($distro =~ /^sles(\d+)$/) { + if ($1 >= 10) { + $webconfdir = '/etc/apache2'; + } + } elsif ($distro =~ /^suse(\d+\.\d+)$/) { + if ($1 >= 10.0) { + $webconfdir = '/etc/apache2'; + } + } my ($release,$timestamp) = split(/\-/,$loncaparev); my (%chksum,%revnum); if (ref($lines) eq 'ARRAY') { @@ -11873,6 +11970,11 @@ sub parse_dns_checksums_tab { if ($version eq $release) { foreach my $line (@{$lines}) { my ($file,$version,$shasum) = split(/,/,$line); + if ($file =~ m{^/etc/httpd/conf}) { + if ($webconfdir eq '/etc/apache2') { + $file =~ s{^\Q/etc/httpd/conf/\E}{$webconfdir/}; + } + } $chksum{$file} = $shasum; $revnum{$file} = $version; } @@ -11890,7 +11992,7 @@ sub parse_dns_checksums_tab { sub fetch_dns_checksums { my %checksums; my $machine_dom = &Apache::lonnet::host_domain($perlvar{'lonHostID'}); - my $loncaparev = &get_server_loncaparev($machine_dom); + my $loncaparev = &get_server_loncaparev($machine_dom,$perlvar{'lonHostID'}); my ($release,$timestamp) = split(/\-/,$loncaparev); &get_dns("/adm/dns/checksums/$release",\&parse_dns_checksums_tab,1,1, \%checksums); @@ -13257,10 +13359,11 @@ $range should be either an integer '100' =item * -putstore($namespace,$symb,$version,$storehash,$udomain,$uname) : +putstore($namespace,$symb,$version,$storehash,$udomain,$uname,$tolog) : replaces a &store() version of data with a replacement set of data for a particular resource in a namespace passed in the $storehash hash -reference +reference. If $tolog is true, the transaction is logged in the courselog +with an action=PUTSTORE. =item * @@ -13414,7 +13517,7 @@ inststatus: types of institutional affil =over =item -inststatustypes, inststatusorder +inststatustypes, inststatusorder, inststatusguest =back @@ -13678,7 +13781,8 @@ filelocation except for hrefs =item * -declutter() : declutters URLs (remove docroot, beginning slashes, 'res' etc) +declutter() : declutters URLs -- remove beginning slashes, 'res' etc. +also removes beginning /home/httpd/html unless /priv/ follows it. =back