--- loncom/lond 2024/12/27 01:04:00 1.582 +++ loncom/lond 2024/12/27 02:32:56 1.583 @@ -2,7 +2,7 @@ # The LearningOnline Network # lond "LON Daemon" Server (port "LOND" 5663) # -# $Id: lond,v 1.582 2024/12/27 01:04:00 raeburn Exp $ +# $Id: lond,v 1.583 2024/12/27 02:32:56 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -65,7 +65,7 @@ my $DEBUG = 0; # Non zero to ena my $status=''; my $lastlog=''; -my $VERSION='$Revision: 1.582 $'; #' stupid emacs +my $VERSION='$Revision: 1.583 $'; #' stupid emacs my $remoteVERSION; my $currenthostid="default"; my $currentdomainid; @@ -223,6 +223,7 @@ my %trust = ( courseidputhash => {remote => 1, domroles => 1, enroll => 1}, courselastaccess => {remote => 1, domroles => 1, enroll => 1}, coursesessions => {institutiononly => 1}, + crsfilefrompriv => {remote => 1, enroll => 1}, currentauth => {remote => 1, domroles => 1, enroll => 1}, currentdump => {remote => 1, enroll => 1}, currentversion => {remote=> 1, content => 1}, @@ -1923,19 +1924,26 @@ sub ls3_handler { my $ulsout=''; my $ulsfn; - my ($crscheck,$toplevel,$currdom,$currnum,$skip); + my ($crscheck,$toplevel,$currdom,$currnum,$skip,$privdir_for_course); unless ($islocal) { my ($major,$minor) = split(/\./,$clientversion); if (($major < 2) || ($major == 2 && $minor < 12)) { $crscheck = 1; } + if ($ulsdir =~ m{^/home/httpd/html/priv/($LONCAPA::match_domain)/($LONCAPA::match_courseid)}) { + my ($currdom,$currnum) = ($1,$2); + if (&LONCAPA::Lond::is_course($currdom,$currnum)) { + $privdir_for_course = 1; + } + } } if (-e $ulsdir) { if(-d $ulsdir) { unless (($getpropath) || ($getuserdir) || ($ulsdir =~ m{^/home/httpd/html/(res/$LONCAPA::match_domain|userfiles/)}) || ($ulsdir =~ m{^/home/httpd/lonUsers/$LONCAPA::match_domain(?:/[\w\-.@]){3}/$LONCAPA::match_name/userfiles}) || - (($ulsdir =~ m{^/home/httpd/html/priv/$LONCAPA::match_domain}) && ($islocal))) { + (($ulsdir =~ m{^/home/httpd/html/priv/$LONCAPA::match_domain}) && ($islocal)) || + ($privdir_for_course)) { &Failure($client,"refused\n",$userinput); return 1; } @@ -2817,6 +2825,92 @@ sub devalidate_meta_cache { } # +# Copy a file from /home/httpd/html/priv/domain/coursenum/ +# to /home/httpd/html/userfiles/domain/coursenum/priv +# +# Parameters: +# $cmd - The command that got us here. +# $tail - Tail of the command +# : separated list of escaped values for +# (a) relative path to a file in /priv/domain/coursenum +# (b) coursenum +# (c) domain +# $client - File descriptor connected to client. +# Returns +# 0 - Requested to exit, caller should shut down. +# 1 - Continue processing. +# + +sub crs_filefrompriv_handler { + my ($cmd, $tail, $client) = @_; + my $userinput = "$cmd:$tail"; + my ($path,$cnum,$cdom) = map { &unescape($_); } split(/:/,$tail); + $path =~ s/\.{2,}//g; + if (($path eq '') || ($path eq '.')) { + &Failure($client, "not_found\n", "$cmd:$tail"); + } else { + $cdom = &LONCAPA::clean_domain($cdom); + $cnum = &LONCAPA::clean_courseid($cnum); + if (&LONCAPA::Lond::is_course($cdom,$cnum)) { + my $toplevel = "/userfiles/$cdom/$cnum/priv"; + my $toppath = $perlvar{'lonDocRoot'}.$toplevel; + my $dest = $toppath.'/'.$path; + my $desturl = $toplevel.'/'.$path; + my $src = $perlvar{'lonDocRoot'}.'/priv/'.$cdom.'/'.$cnum.'/'.$path; + my ($dest_mtime, $src_mtime); + if (-e $dest) { + ($dest_mtime) = (stat($dest))[9]; + } + if (-e $src) { + my $protocol = $Apache::lonnet::protocol{$perlvar{'lonHostID'}}; + $protocol = 'http' if ($protocol ne 'https'); + my $url = $protocol.'://'.&Apache::lonnet::hostname($perlvar{'lonHostID'}).$desturl; + ($src_mtime) = (stat($src))[9]; + if ((-e $dest) && ($dest_mtime >= $src_mtime)) { + my $result = &escape($url); + &Reply($client,\$result,$userinput); + } else { + my $reldir = $toplevel; + my ($subdir,$fname) = ($path =~ m{^(.+)/([^/]+)$}); + if ($subdir eq '') { + $fname = $path; + } else { + $reldir .= '/'.$subdir; + } + my $targetdir = $perlvar{'lonDocRoot'}; + my $dirfail; + foreach my $part (split(/\//,$reldir)) { + $targetdir .= '/'.$part; + if ((-e $targetdir)!=1) { + unless (mkdir($targetdir,0755)) { + $dirfail = 1; + last; + } + } + } + if ($dirfail) { + &Failure($client,"error: mkdir_failed\n", $userinput); + } else { + if (File::Copy::copy($src,$dest)) { + my $result = &escape($url); + &Reply($client,\$result,$userinput); + } else { + &Failure($client,"error: copy_failed\n", $userinput); + } + } + } + } else { + &Failure($client,"error: not_found\n", $userinput); + } + } else { + &Failure($client, "error: not_course\n", $userinput); + } + } + return 1; +} +®ister_handler("crsfilefrompriv", \&crs_filefrompriv_handler, 0, 1, 0); + +# # Fetch a user file from a remote server to the user's home directory # userfiles subdir. # Parameters: